Motivo de la migración 1

Los datos son recopilados de la Encuesta Nacional de Ocupación y Empleo (ENOE), siendo, la fuente principal de información sobre el mercado laboral mexicano al ofrecer datos de manera trimestral de la fuerza de trabajo, ocupación, la informalidad laboral, la subocupación y desocupación.

La ENOE inicia su levantamiento en 2005 y se repite en intervalos regulares de tiempo, captando la información a nivel nacional. Este tipo de encuesta permite captar y conocer de mejor manera las características socioeconómicas de la población mexicana de 15 años y más.

El objetivo del trabajo es implementar y comparar las diferentes series de tiempo de manera jerárquica y permitir el desglose de las causas de migración.

Indicadores

Tomando las preguntas del cuestionario de las cuales son más de trescientas con 150 mil casos a nivel nacional en los diferentes periodos de tiempo.

Se toma como referencia la pregunta cs_ad_mot Motivo de la migración en la cual se desglosa en las siguientes categorías.

\(\bullet\) Trabajo
\(\bullet\) Estudio
\(\bullet\) Se casó o unió
\(\bullet\) Se separó o divorció
\(\bullet\) Problemas de salud
\(\bullet\) Reunirse con la familia
\(\bullet\) Inseguridad pública
\(\bullet\) Falleció
\(\bullet\) Otro Motivo
\(\bullet\) No sabe

De las cuales solo se toman 5 casos para el propósito del presente trabajo.

Base de datos

T.Trabajo <- read.xlsx(paste0(here::here(), "/Base de datos/Resultados ENOE.xlsx"),
                       sheet = "Trabajo", 
                       colNames = TRUE, detectDates = TRUE)
T.Estudio <- read.xlsx(paste0(here::here(), "/Base de datos/Resultados ENOE.xlsx"), 
                       sheet = "Estudio",
                       colNames = TRUE, 
                       detectDates = TRUE)
T.Union <- read.xlsx(paste0(here::here(), "/Base de datos/Resultados ENOE.xlsx"),
                     sheet = "Union",
                     colNames = TRUE, 
                     detectDates = TRUE)
T.Divorcio <- read.xlsx(paste0(here::here(), "/Base de datos/Resultados ENOE.xlsx"), 
                        sheet = "Divorcio", 
                        colNames = TRUE, 
                        detectDates = TRUE)
T.Familia <- read.xlsx(paste0(here::here(), "/Base de datos/Resultados ENOE.xlsx"), 
                       sheet = "Reunirse con un familiar", 
                       colNames = TRUE, 
                       detectDates = TRUE)

Se divide entre la población, debido a que si toman los absolutos de las personas que cambiaron de residencia por alguno de los diferentes motivos de ausencia. Estos tienden a ser mayores en algunas ciudades, debido se tiene mayor densidad de población.

Permitiendo así la comparabilidad entre ciudades por una razón de cada 1000 personas.

#Población Total  
T.Poblacion <- read.xlsx(paste0(here::here(), "/Base de datos/Resultados ENOE.xlsx"), 
                         sheet = "Población", 
                         colNames = TRUE, 
                         detectDates = TRUE)
# Vector de tiempo
Periodo <- T.Poblacion$Periodo #Se guarda el vector tiempo

#Creamos una función personalizada para dividir los elementos desde la segunda columna en adelante
divide_columns <- function(df1, df2) {
                    df1_cols <- df1[, 2:ncol(df1)]
                    df2_cols <- df2[, 2:ncol(df2)]
                    
                    # Aplicamos la división usando map2
                    result_cols <- map2_dfc(df1_cols, df2_cols, ~ .x / .y * 1000)
                    
                    # Reconstruimos el data.frame con la primera columna de df1 y las columnas resultantes
                    result <- bind_cols(df1[, 1, drop = FALSE], result_cols)
                    result
}

tablas <- ls(pattern = "T.")
for(i in 1:6){
  assign(paste0(tablas[i]), divide_columns(get(paste0(tablas[i])), T.Poblacion))
}
# Todo en un data.frame
mydata <- do.call(cbind.data.frame, list(T.Trabajo,
                                         T.Estudio %>% select(-c("Periodo")) ,
                                         T.Union %>% select(-c("Periodo")) ,
                                         T.Divorcio %>% select(-c("Periodo")) ,
                                         T.Familia %>% select(-c("Periodo"))))

El tipo de agregación jerárquico es geográfico donde se agrupan las 32 ciudades autorepresentadas en regiones.

Se consideraron 5 regiones del país para que los cálculos no fueran tan extensos a la hora de interpretarlos.

Estructura jerárquica

Cada uno de estos grupos de desglosan en categorías que están anidadas dentro de las categorías de grupos más grandes como 32 ciudades autorepresentadas y 5 regiones, por lo que se hace una recolección de 160 series de tiempo que siguen una estructura de agregación jerárquica.

Esquema Jerárquico
Esquema Jerárquico

El número de series en el nivel inferior es de 160 series, por lo que las observaciones en el nivel último sumaran a las observaciones del nivel anterior y así sucesivamente.

Los 5 motivos de la ausencia se transforman en series de tiempo, para analizarlos cada uno posteriormente.

ts.Trabajo <- ts(T.Trabajo %>% select(., c(2:length(.))), start = 2005, end = 2019, frequency = 4)
ts.Estudio <- ts(T.Estudio %>% select(., c(2:length(.))), start = 2005, end = 2019, frequency = 4)
ts.Union <- ts(T.Union %>% select(., c(2:length(.))), start = 2005, end = 2019, frequency = 4)
ts.Divorcio <- ts(T.Divorcio %>% select(., c(2:length(.))), start = 2005, end = 2019, frequency = 4)
ts.Familia <- ts(T.Familia %>% select(., c(2:length(.))), start = 2005, end = 2019, frequency = 4)

Motivo de la ausencia: Trabajo

Se analiza cómo caso particular el motivo de la ausencia por trabajo, para empezar familiarizarse con la jerarquización del modelo y posteriormente agregar de manera general los demás motivos expuestos al inicio.

Utilizando la función dygraph permite observar de manera iterativa multiple series de tiempo.

G.Trabajo <- dygraph(ts.Trabajo, main = "Trabajo",  ylab = "Migrantes", xlab = "Periodo") %>%
              dyRangeSelector() %>%
               dyLegend(width = 650) %>%
                dyOptions(colors = RColorBrewer::brewer.pal(32, "Set2")) %>%
                 dyHighlight(highlightSeriesOpts = list(strokeWidth = 2))
G.Trabajo

A continuación, se presenta de manera desagregada un análisis descriptivo de las 32 ciudades autorepresentadas.

Por causas de trabajo la ciudad de Acapulco muestra una media de 4.62 personas que emigraron por trabajo de cada 1000 personas.

Serie de tiempo jerárquica

Se utiliza la función hts para crear una serie de tiempo jerárquica.

Donde se utilizan los datos de último nivel y se utiliza el argumento characters donde los primeros dos caracteres corresponden al primer nivel (Región), los siguientes dos corresponden al segundo nivel (Ciudades) y como último los siete caracteres corresponden al motivo de la ausencia (Trabajo).

#Cambiamos los nombres de las columnas 
Regiones <- c(rep("CE", 7),
              rep("NE", 5), 
              rep("NW", 5), 
              rep("WE", 8),
              rep("SO", 7))
Ciudades <- c("11",     "24",   "01",  "32",    "04",   "14",   "29",   
              "21",     "03",   "06",   "15",   "09",   
              "08",     "19",   "20",   "30",   "18",   
              "12",     "27",   "02",   "05",   "13",   "28",   "22",   "26",   
              "31",     "23",   "07",   "25",   "17",   "10",   "16")
Motivo <- c(rep("Trabajo", 32))

nombres <- paste0(Regiones, Ciudades, Motivo) ## Largo de 11 /Regiones=2,Ciudades=2,Motivo=7
colnames(ts.Trabajo) <- nombres

#Nodos 
Modelo1 <- hts(ts.Trabajo, nodes = list(32), characters = c(2, 2, 7))

## Cambiamos las etiquetas 
Modelo1$labels$`Level 1` <- c("Centro", "Noreste", "Noroeste", "Sureste", "Occidente")
class(Modelo1)
summary(Modelo1)
#p<-smatrix(Modelo1) #Resumen de la matriz de hierarquical time series
#q<-allts(Modelo1) #Matrix de todos los niveles

Nivel 1: Región

Modelo1 %>% 
 aggts(level = 1) %>%
  autoplot(size = 1) + 
   theme_classic() + 
    theme(plot.title = element_text(size = 20),
          plot.subtitle = element_text(size = 12),
          legend.text = element_text(size = 8),
          legend.key.size = unit(0.5, "lines")) +
     scale_color_viridis_d() + 
      scale_color_manual(values = RColorBrewer::brewer.pal(5, "Dark2")) + 
       scale_x_continuous(breaks = seq(2005, 2019, by = 3)) +
        labs(title = "Motivo de la ausencia 2005-2019",
             subtitle = "Trabajo",
             y = "Rate",
             x =  "Year",
             color = "Series") 

La gráfica superior muestra la tasa de migración por trabajo total por región. Donde se puede apreciar que la región Noreste y Noroeste presentan una menor moivilidad con respecto a las demás.

Nivel 2: Ciudad autorepresentada

A continuación se muetran los datos desglosados por las 32 ciudades.

Modelo1 %>% 
 aggts(level = 2) %>%
  autoplot(size = 0.5) + 
   theme_classic() + 
    theme(plot.title = element_text(size = 20, family = "Century Gothic"),
          plot.subtitle = element_text(size = 12, family = "Century Gothic"),
          legend.text = element_text(size = 8, family = "Century Gothic"),
          legend.spacing.x = unit(0.1, "cm"),
          legend.key.size = unit(0.5, "lines"),
          legend.position = "bottom") +
     scale_color_manual(values = colorRampPalette(brewer.pal(8, "Dark2"))(60)) + 
      guides(col = guide_legend(ncol = 15)) +
       labs(title = "Motivo de la ausencia 2005-2019",
            subtitle = "Trabajo",
            y = "Rate",
            x = "Year",
            color = "Series") 

Si bien la gráfica anterior no permite su interpretabilidad debido a que todo el ensamble de las series están muy juntas.

Haciendo uso de la función aggts extrae las series temporales de un objeto hts para cualquier nivel de desagregación.

Para este caso, se están trabajando con dos niveles de desagregación (Regiones y Ciudades) y bien un Nivel Cero (Total).

groups <- aggts(Modelo1, level = 2)

La siguiente gráfica muestra las series de tiempo del nivel inferior, es decir, las tasas de migración por trabajo para cada una de las ciudades en sus respectivas regiones.

Ayudando así a visualizar de manera individual las series.

tibble::as_tibble(groups) %>%
 tidyr::gather(Series) %>%
  mutate(Date = rep(time(groups), NCOL(groups)),
         Group = stringr::str_extract(Series, "([A-Za-z ]*)")) %>%
   ggplot(aes(x = Date, y = value, group = Series, colour = Series)) +
    geom_line() + 
     theme_classic() +
      theme(plot.title = element_text(size = 20, family = "Century Gothic"),
            plot.subtitle = element_text(size = 12, family = "Century Gothic"),
            axis.text.x = element_text(angle = 90, hjust = 1, family = "Century Gothic"),
            legend.text = element_text(size = 8, family = "Century Gothic"),
            legend.spacing.x = unit(0.1, "cm"),
            legend.key.size = unit(0.5, "lines"),
            legend.position = "bottom") +
       scale_color_viridis_d() + 
       #scale_color_manual(values = colorRampPalette(brewer.pal(8, "Set2"))(33)) + 
        scale_x_continuous(breaks = seq(1980, 2015, by = 5)) +
         scale_y_continuous(labels = scales::comma) +
          guides(col = guide_legend(ncol = 15)) +
           labs(title = "Motivo de la ausencia 2005-2019",
                subtitle = "Trabajo",
                y = "Rate",
                x = "Year",
                color = "Grupos") +
            facet_wrap(. ~ Group)

Forecasting: Motivo de trabajo

Utilizando la función forecast() del paquete hts.

Se presentan tres opciones integradas para producir pronósticos usando el parámetro fmethod:

\(\bullet\) ETS Exponential Smoothing,
\(\bullet\) Modelos ARIMA \(\bullet\) Caminatas aleatorias.

Enfoques 2

\(\bullet\) Enfoque de abajo hacia arriba “bottom-up”(method= "bu"): Pronostica del nivel más bajo de la jerarquía, es decir, los motivos de ausencia y luego va agregando los resultados a la jerárquía generar el pronostico del nivel superior al último.

\(\bullet\) Enfoque de arriba hacia abajo “top-down” (method= "tdfp"): Pronostica en la jerarquía del nivel más alto, es decir, por regiones y luego va desglosando los resultados en la jerarquía.

\(\bullet\) Enfoque intermedio **“middle-out” (method= "mo"): Combina enfoques ascendentes y descendentes. Primero, se elige un “nivel medio” y se generan pronósticos para todas las series en este nivel. Para las series por encima del nivel medio, se generan pronósticos coherentes utilizando el enfoque de abajo hacia arriba agregando los pronósticos de “nivel medio” hacia arriba. Para las series por debajo del “nivel medio”, se generan pronósticos coherentes utilizando un enfoque de arriba hacia abajo al desglosar los pronósticos de “nivel medio” hacia abajo.

#h<<-forecast horizon
#method= "mo"<<-"middle-out"
f.modelo1 <- forecast(Modelo1, h = 4, method = "tdfp", fmethod = "ets", parallel = TRUE, keep.fitted = TRUE)
class(f.modelo1)
#summary(f.modelo1)

Nivel 0 al 2

fcst1 <- aggts(f.modelo1, levels = 0:2)
groups <- aggts(Modelo1, levels = 0:2)
autoplot(fcst1, size = 0.5) +
 autolayer(groups) +
  geom_vline(xintercept = 2019, color = "#A8ABD7", linetype= "dashed") +
   theme_classic() +
    theme(plot.title = element_text(size = 18, family = "Century Gothic"),
          plot.subtitle = element_text(size = 14, family = "Century Gothic"),
          legend.text = element_text(size = 7, family = "Century Gothic"),
          legend.key.size = unit(0.5, "lines"),
          legend.position = "bottom") +
     scale_color_viridis_d() + 
      scale_x_continuous(breaks = seq(2005, 2025, by = 2)) +
       scale_y_continuous(labels = scales::comma) +
        guides(col = guide_legend(ncol = 15))+
         labs(title = "Motivo de la ausencia 2005-2019",
              subtitle = "Trabajo",
              y = "Rate",
              x = "Year",
              color = "Series") 
tabla <- ts(rbind(groups, fcst1), start = start(groups), frequency = 4)

Nivel Total: Por motivo de trabajo

#http://www.sthda.com/english/wiki/ggplot2-line-types-how-to-change-line-types-of-a-graph-in-r-software
autoplot(tabla[, "Total"],colour =  "#1720B7", size = 1.2, alpha = 0.6, linetype = "dashed") +
 geom_vline(xintercept = 2019.5, color = "#A8ABD7", linetype = "dashed") +
  theme_classic() +
   scale_x_continuous(breaks = seq(2005, 2025, by = 2)) +
    labs(title = "Motivo de la ausencia 2005-2019",
         subtitle = "Trabajo",
         y = "Rate",
         x =  "Year",
         color = "Series") 
as_tibble(tabla[,-1]) %>%
 tidyr::gather(Series) %>%
  mutate(Date = rep(time(tabla), NCOL(tabla)-1),
         Group = str_extract(Series, "([A-Za-z ]*)")) %>%
   ggplot(aes(x = Date, y = value, group = Series, colour = Series)) +
    geom_line() +
     geom_vline(xintercept = 2017, color = "#A8ABD7", linetype = "dashed") +
      theme_classic() + 
       theme(plot.title = element_text(size = 18, family = "Century Gothic"),
             plot.subtitle = element_text(size = 14, family = "Century Gothic"),
             axis.text.x = element_text(angle = 90, hjust = 1, family = "Century Gothic"),
             legend.position = "bottom",
             legend.text = element_text(size = 8, family = "Century Gothic"),
             legend.key.size = unit(0.5, "lines")) +
        scale_color_viridis_d() +
         scale_x_continuous(breaks = seq(1985, 2025, by = 10)) +
          guides(col = guide_legend(ncol = 15))+
           labs(title = "Motivo de la ausencia 2005-2019",
                subtitle = "Trabajo",
                y = "Rate",
                x = "Year",
                color = "Series") +
            facet_wrap(.~Group) 
f.modelo1 %>% 
 aggts(levels = 0:2) %>%
  autoplot(facet = FALSE) + 
   theme_classic() +
    theme(plot.title = element_text(size = 18, family = "Century Gothic"),
          plot.subtitle = element_text(size = 14, family = "Century Gothic"),
          legend.text = element_text(size = 7, family = "Century Gothic"),
          legend.key.size = unit(0.5, "lines")) +
     scale_color_viridis_d() +
      labs(title = "Motivo de la ausencia 2005-2019",
           subtitle = "Trabajo",
           y = "Rate",
           x = "Year",
           color = "Series")

Motivos de ausencia en general

Utilizando los 5 motivos de ausencia

Serie de tiempo

ts.mydata <- ts(mydata %>% select(., c(2:ncol(.))), start = 2005,end = 2019, frequency = 4)
G.Trabajo<- dygraph(ts.Trabajo, main = "Trabajo", ylab = "Migrantes", xlab = "Periodo") %>%
             dyRangeSelector() %>%
              dyLegend(width = 650) %>%
               dyOptions(colors = RColorBrewer::brewer.pal(32, "Set2")) %>%
                dyHighlight(highlightSeriesOpts = list(strokeWidth = 2))
G.Trabajo
G.Estudio <- dygraph(ts.Estudio, main = "Estudio", ylab = "Migrantes", xlab = "Periodo") %>%
              dyRangeSelector() %>%
               dyLegend(width = 650) %>%
                dyOptions(colors = RColorBrewer::brewer.pal(32, "Set2")) %>%
                 dyHighlight(highlightSeriesOpts = list(strokeWidth = 2))
G.Estudio
G.Union <- dygraph(ts.Union, main = "Se unió o casó", ylab = "Migrantes", xlab = "Periodo") %>%
            dyRangeSelector() %>%
             dyLegend(width = 650) %>%
              dyOptions(colors = RColorBrewer::brewer.pal(32, "Set2")) %>%
               dyHighlight(highlightSeriesOpts = list(strokeWidth = 2))
G.Union
G.Divorcio <- dygraph(ts.Divorcio, main = "Se dicorció o separó", ylab = "Migrantes", xlab = "Periodo") %>%
               dyRangeSelector() %>%
                dyLegend(width = 650) %>%
                 dyOptions(colors = RColorBrewer::brewer.pal(32, "Set2")) %>%
                  dyHighlight(highlightSeriesOpts = list(strokeWidth = 2))
G.Divorcio
G.Familiar <- dygraph(ts.Familia, main = "Reunirse con un familiar", ylab = "Migrantes", xlab = "Periodo") %>%
               dyRangeSelector() %>%
                dyLegend(width = 650) %>%
                 dyOptions(colors = RColorBrewer::brewer.pal(32, "Set2")) %>%
                  dyHighlight(highlightSeriesOpts = list(strokeWidth = 2))
G.Familiar

Modelo jerárquico

Se utiliza la función hts() para crear una serie de tiempo jerárquica.

Donde se utilizan los datos de último nivel y se utiliza el argumento characters donde los primeros dos caracteres corresponden al primer nivel (Región), los siguientes dos corresponden al segundo nivel (Ciudades) y como último los tres caracteres corresponden al motivo de la ausencia.

\(\bullet\) TRA= “Trabajo”
\(\bullet\) EST= “Estudio”
\(\bullet\) UNI= “Se casó o unió”
\(\bullet\) DIV= “Se divorció o separó”
\(\bullet\) FAM= “Reunirse con un familiar”

Regiones <- rep(c(rep("CE", 7),
                  rep("NE", 5),
                  rep("NW", 5),
                  rep("WE", 8),
                  rep("SO", 7)), 5)
Ciudades <- rep(c("11",     "24",   "01",   "32",   "04",   "14",   "29",
                  "21",     "03",   "06",   "15",   "09",
                  "08",     "19",   "20",   "30",   "18",   
                  "12",     "27",   "02",   "05",   "13",   "28",   "22",   "26",   
                  "31",     "23",   "07",   "25",   "17",   "10",   "16"), 5)

Motivo <- c(rep("TRA", 32),
            rep("EST", 32),
            rep("UNI", 32),
            rep("DIV", 32),
            rep("FAM", 32))

nombres <- paste0(Regiones, Ciudades, Motivo) #Largo de 7 | Regiones=2|Ciudades=2|Motivo=3
colnames(ts.mydata) <- nombres

nodes <- list(160, c(5, 32, 5)) #160 variables |Regiones=5|Ciudades=32|Motivos=5|  
Modelo2 <- hts(ts.mydata, nodes = nodes,characters = c(2, 2, 3))

#Cambiamos los labels 
Modelo2$labels$`Level 1` <- c("Centro", "Noreste", "Noroeste", "Sureste", "Occidente")

Nivel 1: Región

Modelo2 %>% 
 aggts(level = 1) %>%
  autoplot(size = 1) + 
   theme_classic() + 
    theme(plot.title = element_text(size = 20),
          plot.subtitle = element_text(size = 12),
          legend.text = element_text(size = 8),
          legend.key.size = unit(0.2, "cm")) +
     scale_color_viridis_d() + 
      scale_color_manual(values = RColorBrewer::brewer.pal(5, "Dark2")) + 
       scale_x_continuous(breaks = seq(2005, 2019, by = 2)) +
        labs(title = "Motivo de la ausencia 2005-2019",
             subtitle = "Trabajo / Estudio / Se casó o unió / Divorció o separó / Reunirse con un familiar",
             y = "Rate",
             x = "Year",
             color = "Series") 

Nivel 2: Cuidad autorepresentada

Modelo2 %>% 
 aggts(level = 2) %>%
  autoplot(size = 0.5) + 
   theme_classic() + 
    theme(plot.title = element_text(size = 20),
          plot.subtitle = element_text(size = 12),
          legend.text = element_text(size = 8),
          legend.key.size = unit(0.5, "lines"),
          legend.position = "bottom") +
     scale_color_manual(values = colorRampPalette(brewer.pal(8, "Dark2"))(60)) + 
      guides(col = guide_legend(ncol = 15))+
       labs(title = "Motivo de la ausencia 2005-2019",
            subtitle = "Trabajo / Estudio / Se casó o unió / Divorció o separó / Reunirse con un familiar",
            y = "Rate",
            x = "Year",
            color = "Series") 

Si bien la gráfica anterior no permite su interpretabilidad debido a que todo el ensamble de las series están muy juntas.

Haciendo uso de la función aggts extrae las series temporales de un objeto hts para cualquier nivel de desagregación.

groups <- aggts(Modelo2, level = 2)
tibble::as_tibble(groups) %>%
 tidyr::gather(Series) %>%
  mutate(Date = rep(time(groups), NCOL(groups)),
         Group =stringr::str_extract(Series, "([A-Za-z ]*)")) %>%
   ggplot(aes(x = Date, y = value, group = Series, colour = Series)) +
    geom_line() + 
     theme_classic() +
      theme(plot.title = element_text(size = 20),
            plot.subtitle = element_text(size = 12),
            axis.text.x = element_text(angle = 90, hjust = 1),
            legend.text = element_text(size = 8),
            legend.key.size = unit(0.5, "lines"),
            legend.position = "bottom") +
       scale_color_viridis_d() +
       #scale_color_manual(values = colorRampPalette(brewer.pal(8, "Dark2"))(33)) + 
        scale_x_continuous(breaks = seq(1980, 2015, by = 5)) +
         scale_y_continuous(labels = scales::comma) +
          guides(col = guide_legend(ncol = 15))+
           labs(title = "Motivo de la ausencia 2005-2019",
                subtitle = "Trabajo / Estudio / Se casó o unió / Divorció o separó / Reunirse con un familiar",
                y = "Rate",
                x = "Year",
                color = "Series") +
            facet_wrap(. ~ Group) 

Nivel 3: Motivo de la ausencia

En modelo general, se están trabajando con tres niveles de desagregación (Motivo de trabajo, Regiones y Ciudades) y bien un Nivel Cero (Total).

groups <- aggts(Modelo2, level = 3)
#https://stringr.tidyverse.org/reference/str_locate.html
tibble::as_tibble(groups) %>%
 tidyr::gather(Series) %>% 
  mutate(Date = rep(time(groups), NCOL(groups)),
         Group =stringr::str_extract(Series, "([A-Za-z ]*)"),
         Motivo=stringr::str_sub(Series,5, 7)) %>%
   ggplot(aes(x = Date, y = value, group = Series, colour = Series)) +
    geom_line() + 
     theme_classic() +
      theme(plot.title = element_text(size = 20),
            plot.subtitle = element_text(size = 12),
            axis.text.x = element_text(angle = 90, hjust = 1),
            legend.text = element_text(size = 8),
            legend.key.width=unit(0.2, "cm"),
            legend.key.height = unit(0, "cm"),
            legend.spacing.x = unit(0, "cm"),
            legend.key.size = unit(0.5, "lines"),
            legend.position = "bottom") +
       scale_color_viridis_d() +
       #scale_color_manual(values = colorRampPalette(brewer.pal(8, "Dark2"))(160)) + 
        scale_x_continuous(breaks = seq(1980, 2015, by = 5)) +
         scale_y_continuous(labels = scales::comma) +
          guides(col = guide_legend(ncol = 15))+
           labs(title = "Motivo de la ausencia 2005-2019",
                subtitle = "Trabajo / Estudio / Se casó o unió / Divorció o separó / Reunirse con un familiar",
                y = "Rate",
                x = "Year",
                color = "Series") +
            facet_wrap(. ~ Group + Motivo) 

Analizando la gráfica anterior el motivo de ausencia para “Reunirse con un familiar” es la que presenta un mayor número de casos migratorios” con respecto a los otros cuatro casos.

#print(Modelo2)
#smatrix(Modelo2)
#allts(Modelo2)

Forecasting: Motivo de la ausencia en general

Se espera que los pronósticos sean consistentes con la estructura de agregación de las series de tiempo al agruparlas.

#h=forescast horizon
#method<-"mo", "bu", "tdfp"
f.modelo2 <- forecast(Modelo2, h = 10, method = "mo", level = 2, fmethod = "arima", parallel = TRUE, keep.fitted = TRUE)
summary(f.modelo2)

Nivel 0 al 2: Total / Región / Ciudad

fcst2 <- aggts(f.modelo2, levels = 0:2)
groups <- aggts(Modelo2, levels = 0:2)
autoplot(fcst2, size = 0.5) +
 autolayer(groups) +
  geom_vline(xintercept = 2019,color = "#A8ABD7", linetype = "dashed") +
   theme_classic() +
    theme(plot.title = element_text(size = 20),
          plot.subtitle = element_text(size = 12),
          legend.text = element_text(size = 7),
          legend.key.size = unit(0.5, "lines"),
          legend.position = "bottom") +
     scale_color_viridis_d() + 
      scale_x_continuous(breaks = seq(2005, 2025, by = 2)) +
       scale_y_continuous(labels = scales::comma) +
        guides(col = guide_legend(ncol = 15))+
         labs(title = "Motivo de la ausencia 2005-2019",
              subtitle = "Trabajo / Estudio / Se casó o unió / Divorció o separó / Reunirse con un familiar",
              y = "Rate",
              x = "Year",
              color = "Series") 
tabla <- ts(rbind(groups, fcst2),
                  start = start(groups), frequency = 4) #Frecuencia al año

Nivel 0: Total de casos de migración

#http://www.sthda.com/english/wiki/ggplot2-line-types-how-to-change-line-types-of-a-graph-in-r-software
autoplot(tabla[, "Total"], colour = "#1720B7", size = 1.2, alpha = 0.6, linetype = "dashed") +      
 geom_vline(xintercept=2019.5,color = "#A8ABD7",linetype= "dashed") +
  theme_classic() +
   theme(plot.title = element_text(size = 20),
         plot.subtitle = element_text(size = 12)) + 
     scale_x_continuous(breaks = seq(2005, 2025, by = 2)) +
     labs(title = "Motivo de la ausencia 2005-2019",
          subtitle = "Trabajo / Estudio / Se casó o unió / Divorció o separó / Reunirse con un familiar",
          y = "Rate",
          x = "Year",
          color = "Series") 

Nivel 1 a 2: Nivel región y nivel ciudad

as_tibble(tabla[,-1]) %>%
 tidyr::gather(Series) %>%
  mutate(Date = rep(time(tabla), NCOL(tabla)-1),
         Group = str_extract(Series, "([A-Za-z ]*)")) %>%
   ggplot(aes(x = Date, y = value, group = Series, colour = Series)) +
    geom_line() +
     geom_vline(xintercept = 2019,color = "#A8ABD7", linetype = "dashed") +
      theme_classic() + 
       theme(plot.title = element_text(size = 20),
             plot.subtitle = element_text(size = 12),
             axis.text.x = element_text(angle = 90, hjust = 1),
             legend.text = element_text(size = 8),
             legend.key.width = unit(0.2, "cm"),
             legend.key.height = unit(0, "cm"),
             legend.spacing.x = unit(0.1, "cm"),
             legend.key.size = unit(0.5, "lines"),
             legend.position = "bottom") +
        scale_color_viridis_d() +
         scale_x_continuous(breaks = seq(2005, 2025,by = 5)) +
          guides(col = guide_legend(ncol = 15)) +
           labs(title = "Motivo de la ausencia 2005-2019",
                subtitle = "Trabajo / Estudio / Se casó o unió / Divorció o separó / Reunirse con un familiar",
                y = "Rate",
                x = "Year",
                color = "Series") +
            facet_wrap(. ~ Group) 

Nivel 3: Motivos de ausencia en general

fcst3 <- aggts(f.modelo2, levels = 3)
groups <- aggts(Modelo2, levels = 3)
tabla <- ts(rbind(groups, fcst3), start = start(groups), frequency = 4) #Frecuencia al año
as_tibble(tabla[,-1]) %>%
 tidyr::gather(Series) %>%
  mutate(Date = rep(time(tabla), NCOL(tabla) - 1),
         Group = str_extract(Series, "([A-Za-z ]*)"),
         Motivo = stringr::str_sub(Series, 5, 7)) %>%
   ggplot(aes(x = Date, y = value, group = Series, colour = Series)) +
    geom_line() +
     geom_vline(xintercept = 2019, color = "#A8ABD7", linetype= "dashed") +
      theme_classic() + 
       theme(plot.title = element_text(size = 20),
             plot.subtitle = element_text(size = 12),
             axis.text.x = element_text(angle=90, hjust=1),
             legend.text = element_text(size = 6),
             legend.key.width=unit(0.2, "cm"),
             legend.key.height = unit(0, "cm"),
             legend.spacing.x = unit(0.1, "cm"),
             legend.key.size = unit(0.01, "lines"),
             legend.position = "bottom") +
        scale_color_viridis_d() +
         scale_x_continuous(breaks = seq(2005, 2025,by = 5)) +
          guides(col = guide_legend(ncol = 15)) +
           labs(title = "Motivo de la ausencia 2005-2019",
                subtitle = "Trabajo / Estudio / Se casó o unió / Divorció o separó / Reunirse con un familiar",
                y = "Rate",
                x = "Year",
                color = "Series") +
            facet_wrap(.~ Group + Motivo)

Referencias

Encuesta Nacional de Ocupación y Empleo (ENOE), población de 15 años y más de edad. (n.d.). Retrieved March 30, 2020, from https://www.inegi.org.mx/programas/enoe/15ymas/

Forecasting Hierarchical Time Series using R - Brillio Data Science - Medium. (n.d.). Retrieved March 30, 2020, from https://medium.com/brillio-data-science/forecasting-hierarchical-time-series-using-r-598828dba435

Librerías

Librerías que se usaron en el trabajo

Nos ha servido a construir modelos de series de tiempo con datos estructurales para fines de pronósticos.

Creative Commons Licence
This work by [Diana Villasana Ocampo]{xmlns:cc= “http://creativecommons.org/ns#” property = “cc:attributionName”} is licensed under a Creative Commons Attribution 4.0 International License.


  1. (https://www.inegi.org.mx/programas/enoe/15ymas/)↩︎

  2. (Forecasting Hierarchical Time Series using R - Brillio Data Science - Medium. (n.d.). Retrieved March 31, 2020, from https://medium.com/brillio-data-science/forecasting-hierarchical-time-series-using-r-598828dba435)↩︎

LS0tDQp0aXRsZTogIkhpZXJhcmNoaWNhbCBUaW1lIFNlcmllcyINCnN1YnRpdGxlOiAiRW5jdWVzdGEgZGUgTmFjaW9uYWwgZGUgT2N1cGFjacOzbiB5IEVtcGxlbyAoRU5PRSkiDQphdXRob3I6ICJEaWFuYSBWaWxsYXNhbmEgT2NhbXBvIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIGNzczogInN0eWxlc3MuY3NzIg0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiAzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiB0cnVlDQotLS0NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNhY2hlID0gVFJVRSwgY2FjaGUubGF6eSA9IEZBTFNFLCBjb2xsYXBzZSA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICNjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIiwNCiAgICAgICAgICAgICAgICAgICAgICBldmFsID0gVFJVRQ0KICAgICAgICAgICAgICAgICAgICAgICkNCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gcnByb2pyb290OjpmaW5kX3JzdHVkaW9fcm9vdF9maWxlKCkpDQpzZXR3ZChoZXJlOjpoZXJlKCkpDQpgYGANCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgcmVzdWx0cz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiNGb250IFN0bHllDQpyZXF1aXJlKHNob3d0ZXh0KQ0KbGlicmFyeShleHRyYWZvbnQpDQp3aW5kb3dzRm9udHMoKQ0KYGBgDQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIHJlc3VsdHM9RkFMU0UsIGV2YWwgPSBUUlVFfQ0KIyBMaWJyZXLDrWFzIGVuIGVsIGRvY3VtZW50bw0KcmVxdWlyZShkeWdyYXBocykNCnJlcXVpcmUoaHRzKQ0KcmVxdWlyZShkYXRhLnRhYmxlKQ0KcmVxdWlyZShvcGVueGxzeCkNCnJlcXVpcmUoZHBseXIpDQpyZXF1aXJlKGthYmxlRXh0cmEpDQpyZXF1aXJlKGtuaXRyKQ0KcmVxdWlyZShnZ3B1YnIpDQpyZXF1aXJlKGdncGxvdDIpDQpyZXF1aXJlKHdlYnNob3QpDQpyZXF1aXJlKGh0bWx3aWRnZXRzKQ0KcmVxdWlyZShzdHJpbmdyKQ0KcmVxdWlyZSh0aWJibGUpDQpyZXF1aXJlKHRpZHlyKQ0KcmVxdWlyZShSQ29sb3JCcmV3ZXIpDQpyZXF1aXJlKHBzeWNoKQ0KbGlicmFyeShwdXJycikNCmBgYA0KDQoNCmBgYHtyLCBlY2hvID0gRkFMU0UsIHJlc3VsdHM9J2FzaXMnLCBldmFsPShvcHRzX2tuaXQkZ2V0KCdybWFya2Rvd24ucGFuZG9jLnRvJykgPT0gJ2xhdGV4Jyl9DQpjYXQoJ1xccGFnZWJyZWFrJykNCmBgYA0KDQojIE1vdGl2byBkZSBsYSBtaWdyYWNpw7NuIFteMV0gICANClteMV06KGh0dHBzOi8vd3d3LmluZWdpLm9yZy5teC9wcm9ncmFtYXMvZW5vZS8xNXltYXMvKSAgDQoNCkxvcyBkYXRvcyBzb24gcmVjb3BpbGFkb3MgZGUgbGEgRW5jdWVzdGEgTmFjaW9uYWwgZGUgT2N1cGFjacOzbiB5IEVtcGxlbyAoRU5PRSksIHNpZW5kbywgbGEgZnVlbnRlIHByaW5jaXBhbCBkZSBpbmZvcm1hY2nDs24gc29icmUgZWwgbWVyY2FkbyBsYWJvcmFsIG1leGljYW5vIGFsIG9mcmVjZXIgZGF0b3MgZGUgbWFuZXJhIHRyaW1lc3RyYWwgZGUgbGEgZnVlcnphIGRlIHRyYWJham8sIG9jdXBhY2nDs24sIGxhIGluZm9ybWFsaWRhZCBsYWJvcmFsLCBsYSBzdWJvY3VwYWNpw7NuIHkgZGVzb2N1cGFjacOzbi4gICANCg0KTGEgRU5PRSBpbmljaWEgc3UgbGV2YW50YW1pZW50byBlbiAyMDA1IHkgc2UgcmVwaXRlIGVuIGludGVydmFsb3MgcmVndWxhcmVzIGRlIHRpZW1wbywgY2FwdGFuZG8gbGEgaW5mb3JtYWNpw7NuIGEgbml2ZWwgbmFjaW9uYWwuIEVzdGUgdGlwbyBkZSBlbmN1ZXN0YSBwZXJtaXRlIGNhcHRhciB5IGNvbm9jZXIgZGUgbWVqb3IgbWFuZXJhIGxhcyBjYXJhY3RlcsOtc3RpY2FzIHNvY2lvZWNvbsOzbWljYXMgZGUgbGEgcG9ibGFjacOzbiBtZXhpY2FuYSBkZSAxNSBhw7FvcyB5IG3DoXMuIA0KDQpFbCBvYmpldGl2byBkZWwgdHJhYmFqbyBlcyBpbXBsZW1lbnRhciB5IGNvbXBhcmFyIGxhcyAgZGlmZXJlbnRlcyBzZXJpZXMgZGUgdGllbXBvIGRlIG1hbmVyYSBqZXLDoXJxdWljYSB5IHBlcm1pdGlyIGVsIGRlc2dsb3NlIGRlIGxhcyBjYXVzYXMgZGUgbWlncmFjacOzbi4gICAgICANCg0KIyMgSW5kaWNhZG9yZXMgDQoNClRvbWFuZG8gbGFzIHByZWd1bnRhcyBkZWwgY3Vlc3Rpb25hcmlvIGRlIGxhcyBjdWFsZXMgc29uIG3DoXMgZGUgdHJlc2NpZW50YXMgY29uIDE1MCBtaWwgY2Fzb3MgYSBuaXZlbCBuYWNpb25hbCBlbiBsb3MgZGlmZXJlbnRlcyBwZXJpb2RvcyBkZSB0aWVtcG8uICAgICAgDQogDQogDQpTZSB0b21hIGNvbW8gcmVmZXJlbmNpYSBsYSBwcmVndW50YSBgY3NfYWRfbW90YCAqKk1vdGl2byBkZSBsYSBtaWdyYWNpw7NuICoqIGVuIGxhIGN1YWwgc2UgZGVzZ2xvc2EgZW4gbGFzIHNpZ3VpZW50ZXMgY2F0ZWdvcsOtYXMuIA0KDQokXGJ1bGxldCQgVHJhYmFqbyAgICAgDQokXGJ1bGxldCQgRXN0dWRpbyAgIA0KJFxidWxsZXQkIFNlIGNhc8OzIG8gdW5pw7MgICAgIA0KJFxidWxsZXQkIFNlIHNlcGFyw7MgbyBkaXZvcmNpw7MgICAgDQokXGJ1bGxldCQgUHJvYmxlbWFzIGRlIHNhbHVkICAgDQokXGJ1bGxldCQgUmV1bmlyc2UgY29uIGxhIGZhbWlsaWEgICAgICAgICAgIA0KJFxidWxsZXQkIEluc2VndXJpZGFkIHDDumJsaWNhICAgICAgDQokXGJ1bGxldCQgRmFsbGVjacOzICAgICAgIA0KJFxidWxsZXQkIE90cm8gTW90aXZvICAgICAgIA0KJFxidWxsZXQkIE5vIHNhYmUgIA0KDQpEZSBsYXMgY3VhbGVzIHNvbG8gc2UgdG9tYW4gNSBjYXNvcyBwYXJhIGVsIHByb3DDs3NpdG8gZGVsIHByZXNlbnRlIHRyYWJham8uICAgDQoNCg0KKipCYXNlIGRlIGRhdG9zKiogICANCg0KYGBge3J9DQpULlRyYWJham8gPC0gcmVhZC54bHN4KHBhc3RlMChoZXJlOjpoZXJlKCksICIvQmFzZSBkZSBkYXRvcy9SZXN1bHRhZG9zIEVOT0UueGxzeCIpLA0KICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9ICJUcmFiYWpvIiwgDQogICAgICAgICAgICAgICAgICAgICAgIGNvbE5hbWVzID0gVFJVRSwgZGV0ZWN0RGF0ZXMgPSBUUlVFKQ0KVC5Fc3R1ZGlvIDwtIHJlYWQueGxzeChwYXN0ZTAoaGVyZTo6aGVyZSgpLCAiL0Jhc2UgZGUgZGF0b3MvUmVzdWx0YWRvcyBFTk9FLnhsc3giKSwgDQogICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gIkVzdHVkaW8iLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2xOYW1lcyA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICBkZXRlY3REYXRlcyA9IFRSVUUpDQpULlVuaW9uIDwtIHJlYWQueGxzeChwYXN0ZTAoaGVyZTo6aGVyZSgpLCAiL0Jhc2UgZGUgZGF0b3MvUmVzdWx0YWRvcyBFTk9FLnhsc3giKSwNCiAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gIlVuaW9uIiwNCiAgICAgICAgICAgICAgICAgICAgIGNvbE5hbWVzID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICBkZXRlY3REYXRlcyA9IFRSVUUpDQpULkRpdm9yY2lvIDwtIHJlYWQueGxzeChwYXN0ZTAoaGVyZTo6aGVyZSgpLCAiL0Jhc2UgZGUgZGF0b3MvUmVzdWx0YWRvcyBFTk9FLnhsc3giKSwgDQogICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9ICJEaXZvcmNpbyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgY29sTmFtZXMgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGRldGVjdERhdGVzID0gVFJVRSkNClQuRmFtaWxpYSA8LSByZWFkLnhsc3gocGFzdGUwKGhlcmU6OmhlcmUoKSwgIi9CYXNlIGRlIGRhdG9zL1Jlc3VsdGFkb3MgRU5PRS54bHN4IiksIA0KICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9ICJSZXVuaXJzZSBjb24gdW4gZmFtaWxpYXIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgY29sTmFtZXMgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgZGV0ZWN0RGF0ZXMgPSBUUlVFKQ0KYGBgDQoNCg0KU2UgZGl2aWRlIGVudHJlIGxhIHBvYmxhY2nDs24sIGRlYmlkbyBhIHF1ZSBzaSB0b21hbiBsb3MgYWJzb2x1dG9zIGRlIGxhcyBwZXJzb25hcyBxdWUgY2FtYmlhcm9uIGRlIHJlc2lkZW5jaWEgcG9yIGFsZ3VubyBkZSBsb3MgZGlmZXJlbnRlcyBtb3Rpdm9zIGRlIGF1c2VuY2lhLiAgRXN0b3MgdGllbmRlbiBhIHNlciBtYXlvcmVzIGVuIGFsZ3VuYXMgY2l1ZGFkZXMsIGRlYmlkbyBzZSB0aWVuZSBtYXlvciBkZW5zaWRhZCBkZSBwb2JsYWNpw7NuLiAgICANCg0KUGVybWl0aWVuZG8gYXPDrSBsYSBjb21wYXJhYmlsaWRhZCBlbnRyZSBjaXVkYWRlcyBwb3IgdW5hIHJhesOzbiBkZSBjYWRhIDEwMDAgcGVyc29uYXMuICAgDQoNCg0KYGBge3J9DQojUG9ibGFjacOzbiBUb3RhbCAgDQpULlBvYmxhY2lvbiA8LSByZWFkLnhsc3gocGFzdGUwKGhlcmU6OmhlcmUoKSwgIi9CYXNlIGRlIGRhdG9zL1Jlc3VsdGFkb3MgRU5PRS54bHN4IiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gIlBvYmxhY2nDs24iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2xOYW1lcyA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRldGVjdERhdGVzID0gVFJVRSkNCiMgVmVjdG9yIGRlIHRpZW1wbw0KUGVyaW9kbyA8LSBULlBvYmxhY2lvbiRQZXJpb2RvICNTZSBndWFyZGEgZWwgdmVjdG9yIHRpZW1wbw0KDQojQ3JlYW1vcyB1bmEgZnVuY2nDs24gcGVyc29uYWxpemFkYSBwYXJhIGRpdmlkaXIgbG9zIGVsZW1lbnRvcyBkZXNkZSBsYSBzZWd1bmRhIGNvbHVtbmEgZW4gYWRlbGFudGUNCmRpdmlkZV9jb2x1bW5zIDwtIGZ1bmN0aW9uKGRmMSwgZGYyKSB7DQogICAgICAgICAgICAgICAgICAgIGRmMV9jb2xzIDwtIGRmMVssIDI6bmNvbChkZjEpXQ0KICAgICAgICAgICAgICAgICAgICBkZjJfY29scyA8LSBkZjJbLCAyOm5jb2woZGYyKV0NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICMgQXBsaWNhbW9zIGxhIGRpdmlzacOzbiB1c2FuZG8gbWFwMg0KICAgICAgICAgICAgICAgICAgICByZXN1bHRfY29scyA8LSBtYXAyX2RmYyhkZjFfY29scywgZGYyX2NvbHMsIH4gLnggLyAueSAqIDEwMDApDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAjIFJlY29uc3RydWltb3MgZWwgZGF0YS5mcmFtZSBjb24gbGEgcHJpbWVyYSBjb2x1bW5hIGRlIGRmMSB5IGxhcyBjb2x1bW5hcyByZXN1bHRhbnRlcw0KICAgICAgICAgICAgICAgICAgICByZXN1bHQgPC0gYmluZF9jb2xzKGRmMVssIDEsIGRyb3AgPSBGQUxTRV0sIHJlc3VsdF9jb2xzKQ0KICAgICAgICAgICAgICAgICAgICByZXN1bHQNCn0NCg0KdGFibGFzIDwtIGxzKHBhdHRlcm4gPSAiVC4iKQ0KZm9yKGkgaW4gMTo2KXsNCiAgYXNzaWduKHBhc3RlMCh0YWJsYXNbaV0pLCBkaXZpZGVfY29sdW1ucyhnZXQocGFzdGUwKHRhYmxhc1tpXSkpLCBULlBvYmxhY2lvbikpDQp9DQpgYGANCg0KYGBge3IsIGVjaG8gPSBUUlVFfQ0KIyBUb2RvIGVuIHVuIGRhdGEuZnJhbWUNCm15ZGF0YSA8LSBkby5jYWxsKGNiaW5kLmRhdGEuZnJhbWUsIGxpc3QoVC5UcmFiYWpvLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBULkVzdHVkaW8gJT4lIHNlbGVjdCgtYygiUGVyaW9kbyIpKSAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFQuVW5pb24gJT4lIHNlbGVjdCgtYygiUGVyaW9kbyIpKSAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFQuRGl2b3JjaW8gJT4lIHNlbGVjdCgtYygiUGVyaW9kbyIpKSAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFQuRmFtaWxpYSAlPiUgc2VsZWN0KC1jKCJQZXJpb2RvIikpKSkNCmBgYA0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KdGFibGEgPC0gaGVhZChteWRhdGFbMTo2XSkNCmtuaXRyOjprYWJsZSh0YWJsYSwNCiAgICAgICAgICAgICBkaWdpdHMgPSAyLA0KICAgICAgICAgICAgIGFsaWduID0gImMiLCANCiAgICAgICAgICAgICBjYXB0aW9uID0gIlRhc2FzIGRlIG1pZ3JhY2nDs24gcG9yIGFsZ8O6biBtb3Rpdm8gZGUgYXVzZW5jaWEiKSAlPiUNCmthYmxlX3N0eWxpbmcocG9zaXRpb24gPSAiY2VudGVyIiwgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIsICJib3JkZXJlZCIsICJob3ZlciIpLA0KICAgICAgICAgICAgICAgIGZvbnRfc2l6ZSA9IDEwKSAlPiUNCmthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IEZBTFNFLCBodG1sX2ZvbnQgPSAiQ2VudHVyeSBHb3RoaWMiKQ0KYGBgDQoNCkVsIHRpcG8gZGUgYWdyZWdhY2nDs24gamVyw6FycXVpY28gZXMgZ2VvZ3LDoWZpY28gZG9uZGUgc2UgYWdydXBhbiBsYXMgMzIgY2l1ZGFkZXMgYXV0b3JlcHJlc2VudGFkYXMgZW4gcmVnaW9uZXMuDQoNClNlIGNvbnNpZGVyYXJvbiA1IHJlZ2lvbmVzIGRlbCBwYcOtcyBwYXJhIHF1ZSBsb3MgY8OhbGN1bG9zIG5vIGZ1ZXJhbiB0YW4gZXh0ZW5zb3MgYSBsYSBob3JhIGRlIGludGVycHJldGFybG9zLiANCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCnRhYmxhIDwtIGRhdGEuZnJhbWUoUmVnaW9uZXMgPSBjKHJlcCgiQ2VudHJvIiwgNyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoIk5vcmVzdGUiLCA1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcCgiTm9yb2VzdGUiLCA1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcCgiT2NjaWRlbnRlIiwgOCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJTdXJlc3RlIiwgNykpLA0KICAgICAgICAgICAgICAgICAgICBDVkVfQ2l1ZGFkID0gYygiMTEiLCAJIjI0IiwgCSIwMSIsIAkiMzIiLCAJIjA0IiwgCSIxNCIsIAkiMjkiLCAJDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMSIsIAkiMDMiLCAJIjA2IiwgCSIxNSIsIAkiMDkiLCAJDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwOCIsIAkiMTkiLCAJIjIwIiwgCSIzMCIsIAkiMTgiLCAJDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMiIsIAkiMjciLCAJIjAyIiwgCSIwNSIsIAkiMTMiLCAJIjI4IiwgCSIyMiIsIAkiMjYiLCAJDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIzMSIsIAkiMjMiLCAJIjA3IiwgCSIyNSIsIAkiMTciLCAJIjEwIiwgCSIxNiIpLA0KICAgICAgICAgICAgICAgICAgICBDaXVkYWQgPSBjKCJBY2FwdWxjbyIsIAkiQ3Vlcm5hdmFjYSIsIAkiTcOpeGljbyIsIAkiUGFjaHVjYSIsIAkiUHVlYmxhIiwgCSJUb2x1Y2EiLCAJIlRsYXhjYWxhIiwgCQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJEdXJhbmdvIiwgCSJNb250ZXJyZXkiLCAJIlNhbiBMdWlzIFBvdG9zw60iLCAJIlNhbHRpbGxvIiwgCSJUYW1waWNvIiwgCQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaGlodWFodWEiLCAJIkN1bGlhY8OhbiIsIAkiSGVybW9zaWxsbyIsIAkiTGEgUGF6IiwgCSJUaWp1YW5hIiwgCQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBZ3Vhc2NhbGllbnRlcyIsIAkiQ29saW1hIiwgCSJHdWFkYWxhamFyYSIsIAkiTGXDs24iLCAJIk1vcmVsaWEiLCAJIlF1ZXLDqXRhcm8iLCAJIlRlcGljIiwgCSJaYWNhdGVjYXMiLCAJDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNhbmPDum4iLCAJIkNhbXBlY2hlIiwgCSJNw6lyaWRhIiwgCSJPYXhhY2EiLCAJIlR1eHRsYSBHdXV0acOpcnJleiIsIAkiVmVyYWNydXoiLCAJIlZpbGxhaGVybW9zYSIpKQ0KDQp0YWJsYSU+JQ0Ka2FibGUoYWxpZ24gPSAiYyIsDQogICAgICBjb2wubmFtZXMgPSBjKCJSZWdpw7NuIiwgIkNsYXZlIiwgIkNpdWRhZCIpLA0KICAgICAgY2FwdGlvbj0gIkVzdHJ1Y3R1cmEgZ2VuZXJhbCBkZSBsYXMgcmVnaW9uZXMiKSAlPiUNCiBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwNCiAgICAgICAgICAgICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiLCAiYm9yZGVyZWQiLCAiaG92ZXIiKSwNCiAgICAgICAgICAgICAgIGZvbnRfc2l6ZSA9IDcsDQogICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJjZW50ZXIiLA0KICAgICAgICAgICAgICAgbGF0ZXhfb3B0aW9ucz0gIkhPTERfcG9zaXRpb24iKSAlPiUgDQogIGdzdWIoImZvbnQtc2l6ZTogaW5pdGlhbCAhaW1wb3J0YW50OyIsICJmb250LXNpemU6IDEwcHQgIWltcG9ydGFudDsiLCAuKSAlPiUNCiAgIGdzdWIoInRleHQtYWxpZ246IGluaXRpYWwgIWltcG9ydGFudDsiLCAidGV4dC1hbGlnbjoganVzdGlmeSAhaW1wb3J0YW50OyIsIC4pDQpgYGANCg0KIyMgRXN0cnVjdHVyYSBqZXLDoXJxdWljYSAgDQoNCkNhZGEgdW5vIGRlIGVzdG9zIGdydXBvcyBkZSBkZXNnbG9zYW4gZW4gY2F0ZWdvcsOtYXMgcXVlIGVzdMOhbiBhbmlkYWRhcyBkZW50cm8gZGUgbGFzIGNhdGVnb3LDrWFzIGRlIGdydXBvcyBtw6FzIGdyYW5kZXMgY29tbyAzMiBjaXVkYWRlcyBhdXRvcmVwcmVzZW50YWRhcyB5IDUgcmVnaW9uZXMsIHBvciBsbyBxdWUgc2UgaGFjZSB1bmEgcmVjb2xlY2Npw7NuIGRlIDE2MCBzZXJpZXMgZGUgdGllbXBvIHF1ZSBzaWd1ZW4gdW5hIGVzdHJ1Y3R1cmEgZGUgYWdyZWdhY2nDs24gamVyw6FycXVpY2EuIA0KDQohW0VzcXVlbWEgSmVyw6FycXVpY29dKEdyYWZpY29zL1JlZ2nDs24uanBnKXt3aWRodD0xMDAlLGhlaWdodD0xMDAlfSANCg0KDQpFbCBuw7ptZXJvIGRlIHNlcmllcyBlbiBlbCBuaXZlbCBpbmZlcmlvciBlcyBkZSAxNjAgc2VyaWVzLCBwb3IgbG8gcXVlIGxhcyBvYnNlcnZhY2lvbmVzIGVuIGVsIG5pdmVsIMO6bHRpbW8gc3VtYXJhbiBhIGxhcyBvYnNlcnZhY2lvbmVzIGRlbCBuaXZlbCBhbnRlcmlvciB5IGFzw60gc3VjZXNpdmFtZW50ZS4gICANCg0KTG9zIDUgbW90aXZvcyBkZSBsYSBhdXNlbmNpYSBzZSB0cmFuc2Zvcm1hbiBlbiBzZXJpZXMgZGUgdGllbXBvLCBwYXJhIGFuYWxpemFybG9zIGNhZGEgdW5vIHBvc3Rlcmlvcm1lbnRlLg0KDQpgYGB7ciwgZWNobyA9IFRSVUV9DQp0cy5UcmFiYWpvIDwtIHRzKFQuVHJhYmFqbyAlPiUgc2VsZWN0KC4sIGMoMjpsZW5ndGgoLikpKSwgc3RhcnQgPSAyMDA1LCBlbmQgPSAyMDE5LCBmcmVxdWVuY3kgPSA0KQ0KdHMuRXN0dWRpbyA8LSB0cyhULkVzdHVkaW8gJT4lIHNlbGVjdCguLCBjKDI6bGVuZ3RoKC4pKSksIHN0YXJ0ID0gMjAwNSwgZW5kID0gMjAxOSwgZnJlcXVlbmN5ID0gNCkNCnRzLlVuaW9uIDwtIHRzKFQuVW5pb24gJT4lIHNlbGVjdCguLCBjKDI6bGVuZ3RoKC4pKSksIHN0YXJ0ID0gMjAwNSwgZW5kID0gMjAxOSwgZnJlcXVlbmN5ID0gNCkNCnRzLkRpdm9yY2lvIDwtIHRzKFQuRGl2b3JjaW8gJT4lIHNlbGVjdCguLCBjKDI6bGVuZ3RoKC4pKSksIHN0YXJ0ID0gMjAwNSwgZW5kID0gMjAxOSwgZnJlcXVlbmN5ID0gNCkNCnRzLkZhbWlsaWEgPC0gdHMoVC5GYW1pbGlhICU+JSBzZWxlY3QoLiwgYygyOmxlbmd0aCguKSkpLCBzdGFydCA9IDIwMDUsIGVuZCA9IDIwMTksIGZyZXF1ZW5jeSA9IDQpDQpgYGANCg0KIyBNb3Rpdm8gZGUgbGEgYXVzZW5jaWE6IFRyYWJham8NCg0KU2UgYW5hbGl6YSBjw7NtbyBjYXNvIHBhcnRpY3VsYXIgZWwgbW90aXZvIGRlIGxhIGF1c2VuY2lhIHBvciB0cmFiYWpvLCBwYXJhIGVtcGV6YXIgIGZhbWlsaWFyaXphcnNlIGNvbiBsYSBqZXJhcnF1aXphY2nDs24gZGVsIG1vZGVsbyB5IHBvc3Rlcmlvcm1lbnRlIGFncmVnYXIgZGUgbWFuZXJhIGdlbmVyYWwgbG9zIGRlbcOhcyBtb3Rpdm9zIGV4cHVlc3RvcyBhbCBpbmljaW8uICAgDQoNClV0aWxpemFuZG8gbGEgZnVuY2nDs24gYGR5Z3JhcGhgIHBlcm1pdGUgb2JzZXJ2YXIgZGUgbWFuZXJhIGl0ZXJhdGl2YSBtdWx0aXBsZSBzZXJpZXMgZGUgdGllbXBvLiAgICANCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCkcuVHJhYmFqbyA8LSBkeWdyYXBoKHRzLlRyYWJham8sIG1haW4gPSAiVHJhYmFqbyIsICB5bGFiID0gIk1pZ3JhbnRlcyIsIHhsYWIgPSAiUGVyaW9kbyIpICU+JQ0KICAgICAgICAgICAgICBkeVJhbmdlU2VsZWN0b3IoKSAlPiUNCiAgICAgICAgICAgICAgIGR5TGVnZW5kKHdpZHRoID0gNjUwKSAlPiUNCiAgICAgICAgICAgICAgICBkeU9wdGlvbnMoY29sb3JzID0gUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDMyLCAiU2V0MiIpKSAlPiUNCiAgICAgICAgICAgICAgICAgZHlIaWdobGlnaHQoaGlnaGxpZ2h0U2VyaWVzT3B0cyA9IGxpc3Qoc3Ryb2tlV2lkdGggPSAyKSkNCkcuVHJhYmFqbw0KYGBgDQoNCmBgYHtyLCBvdXQud2lkdGg9ICIxMTAlIiwgZmlnLmFsaWduPSdjZW50ZXInLGZpZy5jYXA9ICJNb3Rpdm8gZGUgdHJhYmFqbyIsIGV2YWwgPSBGQUxTRSwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkdyYWZpY29zL0dyYWZpY28gVHJhYmFqby5wbmciKQ0KYGBgDQoNCkEgY29udGludWFjacOzbiwgc2UgcHJlc2VudGEgZGUgbWFuZXJhIGRlc2FncmVnYWRhIHVuIGFuw6FsaXNpcyBkZXNjcmlwdGl2byBkZSBsYXMgMzIgY2l1ZGFkZXMgYXV0b3JlcHJlc2VudGFkYXMuIA0KDQpgYGB7cixmaWcuYWxpZ249J2NlbnRlcicsIGVjaG8gPSBGQUxTRX0NCnRhYmxhIDwtIG15ZGF0YVssIGdyZXBsKCJUcmFiYWpvIiwgbmFtZXMobXlkYXRhKSldDQoNCmthYmxlKGRlc2NyaWJlKHRhYmxhKSwNCiAgICAgIGRpZ2l0cyA9IDIsDQogICAgICAgY2FwdGlvbiA9ICJBbsOhbGlzaXMgZGVzY3JpcHRpdm86IE1vdGl2byBkZSB0cmFiYWpvIikgJT4lDQoga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImNvbmRlbnNlZCIpLA0KICAgICAgICAgICAgICAgZm9udF9zaXplID0gOCwNCiAgICAgICAgICAgICAgIHBvc2l0aW9uID0gImNlbnRlciIsDQogICAgICAgICAgICAgICBsYXRleF9vcHRpb25zPSAiSE9MRF9wb3NpdGlvbiIpICU+JQ0KICBrYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGLCBodG1sX2ZvbnQgPSAiQ2VudHVyeSBHb3RoaWMiKSAlPiUgDQogICBnc3ViKCJmb250LXNpemU6IGluaXRpYWwgIWltcG9ydGFudDsiLCAiZm9udC1zaXplOiAxMHB0ICFpbXBvcnRhbnQ7IiwgLikgJT4lDQogICAgZ3N1YigidGV4dC1hbGlnbjogaW5pdGlhbCAhaW1wb3J0YW50OyIsICJ0ZXh0LWFsaWduOiBqdXN0aWZ5ICFpbXBvcnRhbnQ7IiwgLikNCmBgYA0KDQpQb3IgY2F1c2FzIGRlIHRyYWJham8gbGEgY2l1ZGFkIGRlIEFjYXB1bGNvIG11ZXN0cmEgdW5hIG1lZGlhIGRlIDQuNjIgcGVyc29uYXMgcXVlIGVtaWdyYXJvbiBwb3IgdHJhYmFqbyBkZSBjYWRhIDEwMDAgcGVyc29uYXMuICAgDQoNCiMjIFNlcmllIGRlIHRpZW1wbyBqZXLDoXJxdWljYSAgIA0KDQpTZSB1dGlsaXphIGxhIGZ1bmNpw7NuIGBodHNgIHBhcmEgY3JlYXIgdW5hIHNlcmllIGRlIHRpZW1wbyBqZXLDoXJxdWljYS4gDQoNCkRvbmRlIHNlIHV0aWxpemFuIGxvcyBkYXRvcyBkZSDDumx0aW1vIG5pdmVsIHkgc2UgdXRpbGl6YSBlbCBhcmd1bWVudG8gYGNoYXJhY3RlcnNgIGRvbmRlIGxvcyBwcmltZXJvcyBkb3MgY2FyYWN0ZXJlcyBjb3JyZXNwb25kZW4gYWwgcHJpbWVyIG5pdmVsIChSZWdpw7NuKSwgbG9zIHNpZ3VpZW50ZXMgZG9zIGNvcnJlc3BvbmRlbiBhbCBzZWd1bmRvIG5pdmVsIChDaXVkYWRlcykgeSBjb21vIMO6bHRpbW8gbG9zIHNpZXRlIGNhcmFjdGVyZXMgY29ycmVzcG9uZGVuIGFsIG1vdGl2byBkZSBsYSBhdXNlbmNpYSAoVHJhYmFqbykuIA0KDQpgYGB7ciwgZWNobyA9VFJVRX0NCiNDYW1iaWFtb3MgbG9zIG5vbWJyZXMgZGUgbGFzIGNvbHVtbmFzIA0KUmVnaW9uZXMgPC0gYyhyZXAoIkNFIiwgNyksDQogICAgICAgICAgICAgIHJlcCgiTkUiLCA1KSwgDQogICAgICAgICAgICAgIHJlcCgiTlciLCA1KSwgDQogICAgICAgICAgICAgIHJlcCgiV0UiLCA4KSwNCiAgICAgICAgICAgICAgcmVwKCJTTyIsIDcpKQ0KQ2l1ZGFkZXMgPC0gYygiMTEiLCAJIjI0IiwgCSIwMSIsICAiMzIiLCAJIjA0IiwgCSIxNCIsIAkiMjkiLCAJDQogICAgICAgICAgICAgICIyMSIsIAkiMDMiLCAJIjA2IiwgCSIxNSIsIAkiMDkiLCAJDQogICAgICAgICAgICAgICIwOCIsIAkiMTkiLCAJIjIwIiwgCSIzMCIsIAkiMTgiLCAJDQogICAgICAgICAgICAgICIxMiIsIAkiMjciLCAJIjAyIiwgCSIwNSIsIAkiMTMiLCAJIjI4IiwgCSIyMiIsIAkiMjYiLCAJDQogICAgICAgICAgICAgICIzMSIsIAkiMjMiLCAJIjA3IiwgCSIyNSIsIAkiMTciLCAJIjEwIiwgCSIxNiIpDQpNb3Rpdm8gPC0gYyhyZXAoIlRyYWJham8iLCAzMikpDQoNCm5vbWJyZXMgPC0gcGFzdGUwKFJlZ2lvbmVzLCBDaXVkYWRlcywgTW90aXZvKSAjIyBMYXJnbyBkZSAxMSAvUmVnaW9uZXM9MixDaXVkYWRlcz0yLE1vdGl2bz03DQpjb2xuYW1lcyh0cy5UcmFiYWpvKSA8LSBub21icmVzDQoNCiNOb2RvcyANCk1vZGVsbzEgPC0gaHRzKHRzLlRyYWJham8sIG5vZGVzID0gbGlzdCgzMiksIGNoYXJhY3RlcnMgPSBjKDIsIDIsIDcpKQ0KDQojIyBDYW1iaWFtb3MgbGFzIGV0aXF1ZXRhcyANCk1vZGVsbzEkbGFiZWxzJGBMZXZlbCAxYCA8LSBjKCJDZW50cm8iLCAiTm9yZXN0ZSIsICJOb3JvZXN0ZSIsICJTdXJlc3RlIiwgIk9jY2lkZW50ZSIpDQpgYGANCg0KDQpgYGB7ciwgZWNobyA9IFRSVUV9DQpjbGFzcyhNb2RlbG8xKQ0Kc3VtbWFyeShNb2RlbG8xKQ0KI3A8LXNtYXRyaXgoTW9kZWxvMSkgI1Jlc3VtZW4gZGUgbGEgbWF0cml6IGRlIGhpZXJhcnF1aWNhbCB0aW1lIHNlcmllcw0KI3E8LWFsbHRzKE1vZGVsbzEpICNNYXRyaXggZGUgdG9kb3MgbG9zIG5pdmVsZXMNCmBgYA0KDQojIyBOaXZlbCAxOiBSZWdpw7NuDQoNCmBgYHtyLCBlY2hvID0gVFJVRX0NCk1vZGVsbzEgJT4lIA0KIGFnZ3RzKGxldmVsID0gMSkgJT4lDQogIGF1dG9wbG90KHNpemUgPSAxKSArIA0KICAgdGhlbWVfY2xhc3NpYygpICsgDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksDQogICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsICJsaW5lcyIpKSArDQogICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsgDQogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDUsICJEYXJrMiIpKSArIA0KICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwNSwgMjAxOSwgYnkgPSAzKSkgKw0KICAgICAgICBsYWJzKHRpdGxlID0gIk1vdGl2byBkZSBsYSBhdXNlbmNpYSAyMDA1LTIwMTkiLA0KICAgICAgICAgICAgIHN1YnRpdGxlID0gIlRyYWJham8iLA0KICAgICAgICAgICAgIHkgPSAiUmF0ZSIsDQogICAgICAgICAgICAgeCA9ICAiWWVhciIsDQogICAgICAgICAgICAgY29sb3IgPSAiU2VyaWVzIikgDQpgYGANCg0KTGEgZ3LDoWZpY2Egc3VwZXJpb3IgbXVlc3RyYSBsYSB0YXNhIGRlIG1pZ3JhY2nDs24gcG9yIHRyYWJham8gdG90YWwgcG9yIHJlZ2nDs24uIERvbmRlIHNlIHB1ZWRlIGFwcmVjaWFyIHF1ZSBsYSByZWdpw7NuIE5vcmVzdGUgeSBOb3JvZXN0ZSBwcmVzZW50YW4gdW5hIG1lbm9yIG1vaXZpbGlkYWQgY29uIHJlc3BlY3RvIGEgbGFzIGRlbcOhcy4gDQoNCg0KIyMgTml2ZWwgMjogQ2l1ZGFkIGF1dG9yZXByZXNlbnRhZGENCg0KQSBjb250aW51YWNpw7NuIHNlIG11ZXRyYW4gbG9zIGRhdG9zIGRlc2dsb3NhZG9zIHBvciBsYXMgMzIgY2l1ZGFkZXMuIA0KDQpgYGB7cn0NCk1vZGVsbzEgJT4lIA0KIGFnZ3RzKGxldmVsID0gMikgJT4lDQogIGF1dG9wbG90KHNpemUgPSAwLjUpICsgDQogICB0aGVtZV9jbGFzc2ljKCkgKyANCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgZmFtaWx5ID0gIkNlbnR1cnkgR290aGljIiksDQogICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhbWlseSA9ICJDZW50dXJ5IEdvdGhpYyIpLA0KICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4LCBmYW1pbHkgPSAiQ2VudHVyeSBHb3RoaWMiKSwNCiAgICAgICAgICBsZWdlbmQuc3BhY2luZy54ID0gdW5pdCgwLjEsICJjbSIpLA0KICAgICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC41LCAibGluZXMiKSwNCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDgsICJEYXJrMiIpKSg2MCkpICsgDQogICAgICBndWlkZXMoY29sID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAxNSkpICsNCiAgICAgICBsYWJzKHRpdGxlID0gIk1vdGl2byBkZSBsYSBhdXNlbmNpYSAyMDA1LTIwMTkiLA0KICAgICAgICAgICAgc3VidGl0bGUgPSAiVHJhYmFqbyIsDQogICAgICAgICAgICB5ID0gIlJhdGUiLA0KICAgICAgICAgICAgeCA9ICJZZWFyIiwNCiAgICAgICAgICAgIGNvbG9yID0gIlNlcmllcyIpIA0KYGBgDQoNClNpIGJpZW4gbGEgZ3LDoWZpY2EgYW50ZXJpb3Igbm8gcGVybWl0ZSBzdSBpbnRlcnByZXRhYmlsaWRhZCBkZWJpZG8gYSBxdWUgdG9kbyBlbCBlbnNhbWJsZSBkZSBsYXMgc2VyaWVzIGVzdMOhbiBtdXkganVudGFzLiANCg0KSGFjaWVuZG8gdXNvIGRlIGxhIGZ1bmNpw7NuIGBhZ2d0c2AgZXh0cmFlIGxhcyBzZXJpZXMgdGVtcG9yYWxlcyBkZSB1biBvYmpldG8gYGh0c2AgcGFyYSBjdWFscXVpZXIgbml2ZWwgZGUgZGVzYWdyZWdhY2nDs24uIA0KDQpQYXJhIGVzdGUgY2Fzbywgc2UgZXN0w6FuIHRyYWJhamFuZG8gY29uIGRvcyBuaXZlbGVzIGRlIGRlc2FncmVnYWNpw7NuIChSZWdpb25lcyB5IENpdWRhZGVzKSB5IGJpZW4gdW4gTml2ZWwgQ2VybyAoVG90YWwpLg0KDQpgYGB7ciwgZWNobyA9IFRSVUV9DQpncm91cHMgPC0gYWdndHMoTW9kZWxvMSwgbGV2ZWwgPSAyKQ0KYGBgDQoNCkxhIHNpZ3VpZW50ZSBncsOhZmljYSBtdWVzdHJhIGxhcyBzZXJpZXMgZGUgdGllbXBvIGRlbCBuaXZlbCBpbmZlcmlvciwgZXMgZGVjaXIsIGxhcyB0YXNhcyBkZSBtaWdyYWNpw7NuIHBvciB0cmFiYWpvIHBhcmEgY2FkYSB1bmEgZGUgbGFzIGNpdWRhZGVzIGVuIHN1cyByZXNwZWN0aXZhcyByZWdpb25lcy4gIA0KDQpBeXVkYW5kbyBhc8OtIGEgdmlzdWFsaXphciBkZSBtYW5lcmEgaW5kaXZpZHVhbCBsYXMgc2VyaWVzLiAgDQoNCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNX0NCnRpYmJsZTo6YXNfdGliYmxlKGdyb3VwcykgJT4lDQogdGlkeXI6OmdhdGhlcihTZXJpZXMpICU+JQ0KICBtdXRhdGUoRGF0ZSA9IHJlcCh0aW1lKGdyb3VwcyksIE5DT0woZ3JvdXBzKSksDQogICAgICAgICBHcm91cCA9IHN0cmluZ3I6OnN0cl9leHRyYWN0KFNlcmllcywgIihbQS1aYS16IF0qKSIpKSAlPiUNCiAgIGdncGxvdChhZXMoeCA9IERhdGUsIHkgPSB2YWx1ZSwgZ3JvdXAgPSBTZXJpZXMsIGNvbG91ciA9IFNlcmllcykpICsNCiAgICBnZW9tX2xpbmUoKSArIA0KICAgICB0aGVtZV9jbGFzc2ljKCkgKw0KICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhbWlseSA9ICJDZW50dXJ5IEdvdGhpYyIpLA0KICAgICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhbWlseSA9ICJDZW50dXJ5IEdvdGhpYyIpLA0KICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCBmYW1pbHkgPSAiQ2VudHVyeSBHb3RoaWMiKSwNCiAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4LCBmYW1pbHkgPSAiQ2VudHVyeSBHb3RoaWMiKSwNCiAgICAgICAgICAgIGxlZ2VuZC5zcGFjaW5nLnggPSB1bml0KDAuMSwgImNtIiksDQogICAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwgImxpbmVzIiksDQogICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICAgICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsgDQogICAgICAgI3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOCwgIlNldDIiKSkoMzMpKSArIA0KICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDE5ODAsIDIwMTUsIGJ5ID0gNSkpICsNCiAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSArDQogICAgICAgICAgZ3VpZGVzKGNvbCA9IGd1aWRlX2xlZ2VuZChuY29sID0gMTUpKSArDQogICAgICAgICAgIGxhYnModGl0bGUgPSAiTW90aXZvIGRlIGxhIGF1c2VuY2lhIDIwMDUtMjAxOSIsDQogICAgICAgICAgICAgICAgc3VidGl0bGUgPSAiVHJhYmFqbyIsDQogICAgICAgICAgICAgICAgeSA9ICJSYXRlIiwNCiAgICAgICAgICAgICAgICB4ID0gIlllYXIiLA0KICAgICAgICAgICAgICAgIGNvbG9yID0gIkdydXBvcyIpICsNCiAgICAgICAgICAgIGZhY2V0X3dyYXAoLiB+IEdyb3VwKQ0KYGBgDQoNCiMjIEZvcmVjYXN0aW5nOiBNb3Rpdm8gZGUgdHJhYmFqbw0KDQpVdGlsaXphbmRvIGxhIGZ1bmNpw7NuIGBmb3JlY2FzdCgpYCBkZWwgcGFxdWV0ZSBgaHRzYC4gIA0KDQpTZSBwcmVzZW50YW4gdHJlcyBvcGNpb25lcyBpbnRlZ3JhZGFzIHBhcmEgcHJvZHVjaXIgcHJvbsOzc3RpY29zIHVzYW5kbyBlbCBwYXLDoW1ldHJvIGBmbWV0aG9kYDogDQoNCiRcYnVsbGV0JCAqKkVUUyoqIGBFeHBvbmVudGlhbCBTbW9vdGhpbmdgLCAgIA0KJFxidWxsZXQkIE1vZGVsb3MgKipBUklNQSoqIA0KJFxidWxsZXQkIENhbWluYXRhcyBhbGVhdG9yaWFzLiAgICAgDQoNCiMjIyBFbmZvcXVlcyBbXjJdDQpbXjJdOihGb3JlY2FzdGluZyBIaWVyYXJjaGljYWwgVGltZSBTZXJpZXMgdXNpbmcgUiAtIEJyaWxsaW8gRGF0YSBTY2llbmNlIC0gTWVkaXVtLiAobi5kLikuIFJldHJpZXZlZCBNYXJjaCAzMSwgMjAyMCwgZnJvbSBodHRwczovL21lZGl1bS5jb20vYnJpbGxpby1kYXRhLXNjaWVuY2UvZm9yZWNhc3RpbmctaGllcmFyY2hpY2FsLXRpbWUtc2VyaWVzLXVzaW5nLXItNTk4ODI4ZGJhNDM1KQ0KDQokXGJ1bGxldCQgICpFbmZvcXVlIGRlIGFiYWpvIGhhY2lhIGFycmliYSogKioiYm90dG9tLXVwIioqKGBtZXRob2Q9ICJidSJgKTogUHJvbm9zdGljYSBkZWwgbml2ZWwgbcOhcyBiYWpvIGRlIGxhIGplcmFycXXDrWEsIGVzIGRlY2lyLCBsb3MgbW90aXZvcyBkZSBhdXNlbmNpYSB5IGx1ZWdvIHZhIGFncmVnYW5kbyBsb3MgcmVzdWx0YWRvcyBhIGxhIGplcsOhcnF1w61hIGdlbmVyYXIgZWwgcHJvbm9zdGljbyBkZWwgbml2ZWwgc3VwZXJpb3IgYWwgw7psdGltby4gDQoNCiRcYnVsbGV0JCAqRW5mb3F1ZSBkZSBhcnJpYmEgaGFjaWEgYWJham8qICoqInRvcC1kb3duIioqIChgbWV0aG9kPSAidGRmcCJgKTogUHJvbm9zdGljYSBlbiBsYSBqZXJhcnF1w61hIGRlbCBuaXZlbCBtw6FzIGFsdG8sIGVzIGRlY2lyLCBwb3IgcmVnaW9uZXMgeSBsdWVnbyB2YSBkZXNnbG9zYW5kbyBsb3MgcmVzdWx0YWRvcyBlbiBsYSBqZXJhcnF1w61hLiAgIA0KDQokXGJ1bGxldCQgICpFbmZvcXVlIGludGVybWVkaW8qICoqIm1pZGRsZS1vdXQiIChgbWV0aG9kPSAibW8iYCk6IENvbWJpbmEgZW5mb3F1ZXMgYXNjZW5kZW50ZXMgeSBkZXNjZW5kZW50ZXMuIFByaW1lcm8sIHNlIGVsaWdlIHVuICJuaXZlbCBtZWRpbyIgeSBzZSBnZW5lcmFuIHByb27Ds3N0aWNvcyBwYXJhIHRvZGFzIGxhcyBzZXJpZXMgZW4gZXN0ZSBuaXZlbC4gUGFyYSBsYXMgc2VyaWVzIHBvciBlbmNpbWEgZGVsIG5pdmVsIG1lZGlvLCBzZSBnZW5lcmFuIHByb27Ds3N0aWNvcyBjb2hlcmVudGVzIHV0aWxpemFuZG8gZWwgZW5mb3F1ZSBkZSBhYmFqbyBoYWNpYSBhcnJpYmEgYWdyZWdhbmRvIGxvcyBwcm9uw7NzdGljb3MgZGUgIm5pdmVsIG1lZGlvIiBoYWNpYSBhcnJpYmEuIFBhcmEgbGFzIHNlcmllcyBwb3IgZGViYWpvIGRlbCAibml2ZWwgbWVkaW8iLCBzZSBnZW5lcmFuIHByb27Ds3N0aWNvcyBjb2hlcmVudGVzIHV0aWxpemFuZG8gdW4gZW5mb3F1ZSBkZSBhcnJpYmEgaGFjaWEgYWJham8gYWwgZGVzZ2xvc2FyIGxvcyBwcm9uw7NzdGljb3MgZGUgIm5pdmVsIG1lZGlvIiBoYWNpYSBhYmFqby4gICAgICANCg0KYGBge3IsIGVjaG8gPSBUUlVFfQ0KI2g8PC1mb3JlY2FzdCBob3Jpem9uDQojbWV0aG9kPSAibW8iPDwtIm1pZGRsZS1vdXQiDQpmLm1vZGVsbzEgPC0gZm9yZWNhc3QoTW9kZWxvMSwgaCA9IDQsIG1ldGhvZCA9ICJ0ZGZwIiwgZm1ldGhvZCA9ICJldHMiLCBwYXJhbGxlbCA9IFRSVUUsIGtlZXAuZml0dGVkID0gVFJVRSkNCmBgYA0KDQpgYGB7cixlY2hvID0gVFJVRX0NCmNsYXNzKGYubW9kZWxvMSkNCiNzdW1tYXJ5KGYubW9kZWxvMSkNCmBgYA0KDQojIyMgTml2ZWwgMCBhbCAyIA0KDQpgYGB7cixlY2hvID0gVFJVRX0NCmZjc3QxIDwtIGFnZ3RzKGYubW9kZWxvMSwgbGV2ZWxzID0gMDoyKQ0KZ3JvdXBzIDwtIGFnZ3RzKE1vZGVsbzEsIGxldmVscyA9IDA6MikNCmBgYA0KDQpgYGB7cixmaWcud2lkdGggPSA4LGZpZy5oZWlnaHQgPSA1fQ0KYXV0b3Bsb3QoZmNzdDEsIHNpemUgPSAwLjUpICsNCiBhdXRvbGF5ZXIoZ3JvdXBzKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMTksIGNvbG9yID0gIiNBOEFCRDciLCBsaW5ldHlwZT0gImRhc2hlZCIpICsNCiAgIHRoZW1lX2NsYXNzaWMoKSArDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhbWlseSA9ICJDZW50dXJ5IEdvdGhpYyIpLA0KICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBmYW1pbHkgPSAiQ2VudHVyeSBHb3RoaWMiKSwNCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgZmFtaWx5ID0gIkNlbnR1cnkgR290aGljIiksDQogICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsICJsaW5lcyIpLA0KICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArDQogICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsgDQogICAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDUsIDIwMjUsIGJ5ID0gMikpICsNCiAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKw0KICAgICAgICBndWlkZXMoY29sID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAxNSkpKw0KICAgICAgICAgbGFicyh0aXRsZSA9ICJNb3Rpdm8gZGUgbGEgYXVzZW5jaWEgMjAwNS0yMDE5IiwNCiAgICAgICAgICAgICAgc3VidGl0bGUgPSAiVHJhYmFqbyIsDQogICAgICAgICAgICAgIHkgPSAiUmF0ZSIsDQogICAgICAgICAgICAgIHggPSAiWWVhciIsDQogICAgICAgICAgICAgIGNvbG9yID0gIlNlcmllcyIpIA0KYGBgDQoNCg0KYGBge3IsZWNobyA9IFRSVUV9DQp0YWJsYSA8LSB0cyhyYmluZChncm91cHMsIGZjc3QxKSwgc3RhcnQgPSBzdGFydChncm91cHMpLCBmcmVxdWVuY3kgPSA0KQ0KYGBgDQoNCiMjIyBOaXZlbCBUb3RhbDogUG9yIG1vdGl2byBkZSB0cmFiYWpvDQoNCmBgYHtyfQ0KI2h0dHA6Ly93d3cuc3RoZGEuY29tL2VuZ2xpc2gvd2lraS9nZ3Bsb3QyLWxpbmUtdHlwZXMtaG93LXRvLWNoYW5nZS1saW5lLXR5cGVzLW9mLWEtZ3JhcGgtaW4tci1zb2Z0d2FyZQ0KYXV0b3Bsb3QodGFibGFbLCAiVG90YWwiXSxjb2xvdXIgPSAgIiMxNzIwQjciLCBzaXplID0gMS4yLCBhbHBoYSA9IDAuNiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMTkuNSwgY29sb3IgPSAiI0E4QUJENyIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwNSwgMjAyNSwgYnkgPSAyKSkgKw0KICAgIGxhYnModGl0bGUgPSAiTW90aXZvIGRlIGxhIGF1c2VuY2lhIDIwMDUtMjAxOSIsDQogICAgICAgICBzdWJ0aXRsZSA9ICJUcmFiYWpvIiwNCiAgICAgICAgIHkgPSAiUmF0ZSIsDQogICAgICAgICB4ID0gICJZZWFyIiwNCiAgICAgICAgIGNvbG9yID0gIlNlcmllcyIpIA0KYGBgDQoNCmBgYHtyLGZpZy53aWR0aCA9IDEwLGZpZy5oZWlnaHQgPSA1fQ0KYXNfdGliYmxlKHRhYmxhWywtMV0pICU+JQ0KIHRpZHlyOjpnYXRoZXIoU2VyaWVzKSAlPiUNCiAgbXV0YXRlKERhdGUgPSByZXAodGltZSh0YWJsYSksIE5DT0wodGFibGEpLTEpLA0KICAgICAgICAgR3JvdXAgPSBzdHJfZXh0cmFjdChTZXJpZXMsICIoW0EtWmEteiBdKikiKSkgJT4lDQogICBnZ3Bsb3QoYWVzKHggPSBEYXRlLCB5ID0gdmFsdWUsIGdyb3VwID0gU2VyaWVzLCBjb2xvdXIgPSBTZXJpZXMpKSArDQogICAgZ2VvbV9saW5lKCkgKw0KICAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDE3LCBjb2xvciA9ICIjQThBQkQ3IiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICAgICAgdGhlbWVfY2xhc3NpYygpICsgDQogICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhbWlseSA9ICJDZW50dXJ5IEdvdGhpYyIpLA0KICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBmYW1pbHkgPSAiQ2VudHVyeSBHb3RoaWMiKSwNCiAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEsIGZhbWlseSA9ICJDZW50dXJ5IEdvdGhpYyIpLA0KICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4LCBmYW1pbHkgPSAiQ2VudHVyeSBHb3RoaWMiKSwNCiAgICAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwgImxpbmVzIikpICsNCiAgICAgICAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkgKw0KICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxOTg1LCAyMDI1LCBieSA9IDEwKSkgKw0KICAgICAgICAgIGd1aWRlcyhjb2wgPSBndWlkZV9sZWdlbmQobmNvbCA9IDE1KSkrDQogICAgICAgICAgIGxhYnModGl0bGUgPSAiTW90aXZvIGRlIGxhIGF1c2VuY2lhIDIwMDUtMjAxOSIsDQogICAgICAgICAgICAgICAgc3VidGl0bGUgPSAiVHJhYmFqbyIsDQogICAgICAgICAgICAgICAgeSA9ICJSYXRlIiwNCiAgICAgICAgICAgICAgICB4ID0gIlllYXIiLA0KICAgICAgICAgICAgICAgIGNvbG9yID0gIlNlcmllcyIpICsNCiAgICAgICAgICAgIGZhY2V0X3dyYXAoLn5Hcm91cCkgDQpgYGANCg0KDQpgYGB7cixldmFsPUZBTFNFfQ0KZi5tb2RlbG8xICU+JSANCiBhZ2d0cyhsZXZlbHMgPSAwOjIpICU+JQ0KICBhdXRvcGxvdChmYWNldCA9IEZBTFNFKSArIA0KICAgdGhlbWVfY2xhc3NpYygpICsNCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFtaWx5ID0gIkNlbnR1cnkgR290aGljIiksDQogICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhbWlseSA9ICJDZW50dXJ5IEdvdGhpYyIpLA0KICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3LCBmYW1pbHkgPSAiQ2VudHVyeSBHb3RoaWMiKSwNCiAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwgImxpbmVzIikpICsNCiAgICAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkgKw0KICAgICAgbGFicyh0aXRsZSA9ICJNb3Rpdm8gZGUgbGEgYXVzZW5jaWEgMjAwNS0yMDE5IiwNCiAgICAgICAgICAgc3VidGl0bGUgPSAiVHJhYmFqbyIsDQogICAgICAgICAgIHkgPSAiUmF0ZSIsDQogICAgICAgICAgIHggPSAiWWVhciIsDQogICAgICAgICAgIGNvbG9yID0gIlNlcmllcyIpDQpgYGANCg0KIyBNb3Rpdm9zIGRlIGF1c2VuY2lhIGVuIGdlbmVyYWwNCg0KVXRpbGl6YW5kbyBsb3MgNSBtb3Rpdm9zIGRlIGF1c2VuY2lhIA0KDQpTZXJpZSBkZSB0aWVtcG8gDQoNCmBgYHtyLCBlY2hvID0gVFJVRX0NCnRzLm15ZGF0YSA8LSB0cyhteWRhdGEgJT4lIHNlbGVjdCguLCBjKDI6bmNvbCguKSkpLCBzdGFydCA9IDIwMDUsZW5kID0gMjAxOSwgZnJlcXVlbmN5ID0gNCkNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KRy5UcmFiYWpvPC0gZHlncmFwaCh0cy5UcmFiYWpvLCBtYWluID0gIlRyYWJham8iLCB5bGFiID0gIk1pZ3JhbnRlcyIsIHhsYWIgPSAiUGVyaW9kbyIpICU+JQ0KICAgICAgICAgICAgIGR5UmFuZ2VTZWxlY3RvcigpICU+JQ0KICAgICAgICAgICAgICBkeUxlZ2VuZCh3aWR0aCA9IDY1MCkgJT4lDQogICAgICAgICAgICAgICBkeU9wdGlvbnMoY29sb3JzID0gUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDMyLCAiU2V0MiIpKSAlPiUNCiAgICAgICAgICAgICAgICBkeUhpZ2hsaWdodChoaWdobGlnaHRTZXJpZXNPcHRzID0gbGlzdChzdHJva2VXaWR0aCA9IDIpKQ0KRy5UcmFiYWpvDQpgYGANCg0KYGBge3Isb3V0LndpZHRoPSAiMTAwJSIsIGZpZy5hbGlnbj0nY2VudGVyJyxmaWcuY2FwPSAiTW90aXZvOiBUcmFiYWpvIiwgZXZhbCA9IEZBTFNFLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiR3JhZmljb3MvR3JhZmljbyBUcmFiYWpvLnBuZyIpDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCkcuRXN0dWRpbyA8LSBkeWdyYXBoKHRzLkVzdHVkaW8sIG1haW4gPSAiRXN0dWRpbyIsIHlsYWIgPSAiTWlncmFudGVzIiwgeGxhYiA9ICJQZXJpb2RvIikgJT4lDQogICAgICAgICAgICAgIGR5UmFuZ2VTZWxlY3RvcigpICU+JQ0KICAgICAgICAgICAgICAgZHlMZWdlbmQod2lkdGggPSA2NTApICU+JQ0KICAgICAgICAgICAgICAgIGR5T3B0aW9ucyhjb2xvcnMgPSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoMzIsICJTZXQyIikpICU+JQ0KICAgICAgICAgICAgICAgICBkeUhpZ2hsaWdodChoaWdobGlnaHRTZXJpZXNPcHRzID0gbGlzdChzdHJva2VXaWR0aCA9IDIpKQ0KRy5Fc3R1ZGlvDQpgYGANCg0KYGBge3Isb3V0LndpZHRoPSAiMTAwJSIsIGZpZy5hbGlnbj0nY2VudGVyJyxmaWcuY2FwPSAiTW90aXZvOiBFc3R1ZGlvIiwgZXZhbCA9IEZBTFNFLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiR3JhZmljb3MvR3JhZmljbyBFc3R1ZGlvLnBuZyIpDQpgYGANCg0KYGBge3IsIGZpZy5hbGlnbj0nY2VudGVyJywgZWNobyA9IEZBTFNFfQ0KdGFibGEgPC0gbXlkYXRhWywgZ3JlcGwoIkVzdHVkaW8iLCBuYW1lcyhteWRhdGEpKV0NCg0Ka2FibGUoZGVzY3JpYmUodGFibGEpLA0KICAgICAgZGlnaXRzID0gMiwNCiAgICAgIGNhcHRpb24gPSAiQW5hbGlzaXMgZGVzY3JpcHRpdm86IEVzdHVkaW8iKSAlPiUNCiBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwNCiAgICAgICAgICAgICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiLCAiYm9yZGVyZWQiLCAiaG92ZXIiKSwNCiAgICAgICAgICAgICAgIGZvbnRfc2l6ZSA9IDcsDQogICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJjZW50ZXIiLA0KICAgICAgICAgICAgICAgbGF0ZXhfb3B0aW9ucz0gIkhPTERfcG9zaXRpb24iKSAlPiUgDQogIGdzdWIoImZvbnQtc2l6ZTogaW5pdGlhbCAhaW1wb3J0YW50OyIsICJmb250LXNpemU6IDEwcHQgIWltcG9ydGFudDsiLCAuKSAlPiUNCiAgIGdzdWIoInRleHQtYWxpZ246IGluaXRpYWwgIWltcG9ydGFudDsiLCAidGV4dC1hbGlnbjoganVzdGlmeSAhaW1wb3J0YW50OyIsIC4pDQpgYGANCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpHLlVuaW9uIDwtIGR5Z3JhcGgodHMuVW5pb24sIG1haW4gPSAiU2UgdW5pw7MgbyBjYXPDsyIsIHlsYWIgPSAiTWlncmFudGVzIiwgeGxhYiA9ICJQZXJpb2RvIikgJT4lDQogICAgICAgICAgICBkeVJhbmdlU2VsZWN0b3IoKSAlPiUNCiAgICAgICAgICAgICBkeUxlZ2VuZCh3aWR0aCA9IDY1MCkgJT4lDQogICAgICAgICAgICAgIGR5T3B0aW9ucyhjb2xvcnMgPSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoMzIsICJTZXQyIikpICU+JQ0KICAgICAgICAgICAgICAgZHlIaWdobGlnaHQoaGlnaGxpZ2h0U2VyaWVzT3B0cyA9IGxpc3Qoc3Ryb2tlV2lkdGggPSAyKSkNCkcuVW5pb24NCmBgYA0KDQpgYGB7cixvdXQud2lkdGg9ICIxMDAlIiwgZmlnLmFsaWduPSdjZW50ZXInLGZpZy5jYXA9ICJNb3Rpdm86IFNlIHVuacOzIG8gY2Fzw7MiLCBldmFsID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJHcmFmaWNvcy9HcmFmaWNvIFVuaW9uLnBuZyIpDQpgYGANCg0KDQoNCmBgYHtyLGZpZy5hbGlnbj0nY2VudGVyJywgZWNobyA9IEZBTFNFfQ0KdGFibGEgPC0gbXlkYXRhWywgZ3JlcGwoIlVuaW9uIiwgbmFtZXMobXlkYXRhKSldDQoNCmthYmxlKGRlc2NyaWJlKHRhYmxhKSwNCiAgICAgIGRpZ2l0cyA9IDIsDQogICAgICBjYXB0aW9uID0gIkFuYWxpc2lzIGRlc2NyaXB0aXZvOiBTZSB1bmnDsyBvIGNhc8OzIikgJT4lDQoga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsDQogICAgICAgICAgICAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoImNvbmRlbnNlZCIsICJyZXNwb25zaXZlIiwgImJvcmRlcmVkIiwgImhvdmVyIiksDQogICAgICAgICAgICAgICBmb250X3NpemUgPSA3LA0KICAgICAgICAgICAgICAgcG9zaXRpb24gPSAiY2VudGVyIiwNCiAgICAgICAgICAgICAgIGxhdGV4X29wdGlvbnM9ICJIT0xEX3Bvc2l0aW9uIikgJT4lIA0KICBnc3ViKCJmb250LXNpemU6IGluaXRpYWwgIWltcG9ydGFudDsiLCAiZm9udC1zaXplOiAxMHB0ICFpbXBvcnRhbnQ7IiwgLikgJT4lDQogICBnc3ViKCJ0ZXh0LWFsaWduOiBpbml0aWFsICFpbXBvcnRhbnQ7IiwgInRleHQtYWxpZ246IGp1c3RpZnkgIWltcG9ydGFudDsiLCAuKQ0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpHLkRpdm9yY2lvIDwtIGR5Z3JhcGgodHMuRGl2b3JjaW8sIG1haW4gPSAiU2UgZGljb3JjacOzIG8gc2VwYXLDsyIsIHlsYWIgPSAiTWlncmFudGVzIiwgeGxhYiA9ICJQZXJpb2RvIikgJT4lDQogICAgICAgICAgICAgICBkeVJhbmdlU2VsZWN0b3IoKSAlPiUNCiAgICAgICAgICAgICAgICBkeUxlZ2VuZCh3aWR0aCA9IDY1MCkgJT4lDQogICAgICAgICAgICAgICAgIGR5T3B0aW9ucyhjb2xvcnMgPSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoMzIsICJTZXQyIikpICU+JQ0KICAgICAgICAgICAgICAgICAgZHlIaWdobGlnaHQoaGlnaGxpZ2h0U2VyaWVzT3B0cyA9IGxpc3Qoc3Ryb2tlV2lkdGggPSAyKSkNCkcuRGl2b3JjaW8NCmBgYA0KDQpgYGB7cixvdXQud2lkdGg9ICIxMDAlIiwgZmlnLmFsaWduPSdjZW50ZXInLGZpZy5jYXA9ICJNb3Rpdm86IFNlIHNlcGFyw7MgbyBkaXZvcmNpw7MiLCBldmFsID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJHcmFmaWNvcy9HcmFmaWNvIERpdm9yY2lvLnBuZyIpDQpgYGANCg0KYGBge3IsZmlnLmFsaWduPSdjZW50ZXInLCBlY2hvID0gRkFMU0V9DQp0YWJsYSA8LSBteWRhdGFbLCBncmVwbCgiRGl2b3JjaW8iLCBuYW1lcyhteWRhdGEpKV0NCg0Ka2FibGUoZGVzY3JpYmUodGFibGEpLA0KICAgICAgZGlnaXRzID0gMiwNCiAgICAgIGNhcHRpb24gPSAiQW5hbGlzaXMgZGVzY3JpcHRpdm86IFNlIHNlcGFyw7MgbyBkaXZvcmNpw7MiKSAlPiUNCiBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwNCiAgICAgICAgICAgICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiLCAiYm9yZGVyZWQiLCAiaG92ZXIiKSwNCiAgICAgICAgICAgICAgIGZvbnRfc2l6ZSA9IDcsDQogICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJjZW50ZXIiLA0KICAgICAgICAgICAgICAgbGF0ZXhfb3B0aW9ucz0gIkhPTERfcG9zaXRpb24iKSAlPiUgDQogIGdzdWIoImZvbnQtc2l6ZTogaW5pdGlhbCAhaW1wb3J0YW50OyIsICJmb250LXNpemU6IDEwcHQgIWltcG9ydGFudDsiLCAuKSAlPiUNCiAgIGdzdWIoInRleHQtYWxpZ246IGluaXRpYWwgIWltcG9ydGFudDsiLCAidGV4dC1hbGlnbjoganVzdGlmeSAhaW1wb3J0YW50OyIsIC4pDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCkcuRmFtaWxpYXIgPC0gZHlncmFwaCh0cy5GYW1pbGlhLCBtYWluID0gIlJldW5pcnNlIGNvbiB1biBmYW1pbGlhciIsIHlsYWIgPSAiTWlncmFudGVzIiwgeGxhYiA9ICJQZXJpb2RvIikgJT4lDQogICAgICAgICAgICAgICBkeVJhbmdlU2VsZWN0b3IoKSAlPiUNCiAgICAgICAgICAgICAgICBkeUxlZ2VuZCh3aWR0aCA9IDY1MCkgJT4lDQogICAgICAgICAgICAgICAgIGR5T3B0aW9ucyhjb2xvcnMgPSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoMzIsICJTZXQyIikpICU+JQ0KICAgICAgICAgICAgICAgICAgZHlIaWdobGlnaHQoaGlnaGxpZ2h0U2VyaWVzT3B0cyA9IGxpc3Qoc3Ryb2tlV2lkdGggPSAyKSkNCkcuRmFtaWxpYXINCmBgYA0KDQpgYGB7cixvdXQud2lkdGg9ICIxMDAlIiwgZmlnLmFsaWduPSdjZW50ZXInLGZpZy5jYXA9ICJNb3Rpdm86IFJldW5pcnNlIGNvbiB1biBmYW1pbGlhciIsIGV2YWwgPSBGQUxTRSwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkdyYWZpY29zL0dyYWZpY28gRmFtaWxpYXIucG5nIikNCmBgYA0KDQpgYGB7ciwgZmlnLmFsaWduPSdjZW50ZXInLCBlY2hvID0gRkFMU0V9DQp0YWJsYSA8LSBteWRhdGFbLCBncmVwbCgiRmFtaWxpYXIiLCBuYW1lcyhteWRhdGEpKV0NCg0Ka2FibGUoZGVzY3JpYmUodGFibGEpLA0KICAgICAgZGlnaXRzID0gMiwNCiAgICAgIGNhcHRpb24gPSAiQW5hbGlzaXMgZGVzY3JpcHRpdm86IFJldW5pcnNlIGNvbiB1biBmYW1pbGlhciIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwNCiAgICAgICAgICAgICAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiKSwNCiAgICAgICAgICAgICAgICBmb250X3NpemUgPSA3LA0KICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gImNlbnRlciIsDQogICAgICAgICAgICAgICAgbGF0ZXhfb3B0aW9ucz0gIkhPTERfcG9zaXRpb24iKQ0KYGBgDQoNCmBgYHtyLGV2YWw9RkFMU0UsIGVjaG8gPSBGQUxTRX0NCiNodHRwczovL2dpdGh1Yi5jb20vcnN0dWRpby9keWdyYXBocy9pc3N1ZXMvNzENCnNhdmVXaWRnZXQoRy5UcmFiYWpvLCAiR3JhZmljbyBUcmFiYWpvLmh0bWwiLCBzZWxmY29udGFpbmVkID0gVFJVRSwgbGliZGlyID0gTlVMTCkNCnNhdmVXaWRnZXQoRy5Fc3R1ZGlvLCAiR3JhZmljbyBFc3R1ZGlvLmh0bWwiLCBzZWxmY29udGFpbmVkID0gVFJVRSwgbGliZGlyID0gTlVMTCkNCnNhdmVXaWRnZXQoRy5VbmlvbiwgIkdyYWZpY28gVW5pb24uaHRtbCIsIHNlbGZjb250YWluZWQgPSBUUlVFLCBsaWJkaXIgPSBOVUxMKQ0Kc2F2ZVdpZGdldChHLkRpdm9yY2lvLCAiR3JhZmljbyBEaXZvcmNpby5odG1sIiwgc2VsZmNvbnRhaW5lZCA9IFRSVUUsIGxpYmRpciA9IE5VTEwpDQpzYXZlV2lkZ2V0KEcuRmFtaWxpYXIsICJHcmFmaWNvIEZhbWlsaWFyLmh0bWwiLCBzZWxmY29udGFpbmVkID0gVFJVRSwgbGliZGlyID0gTlVMTCkNCg0Kd2lkdGg8LSAxMDgwDQpoZWlnaHQgPC0gNjEwDQojU2UgY29udmllcnRlbiBkZSBodG1sIGEgLnBkZg0Kd2Vic2hvdCh1cmwgPSAiR3JhZmljbyBUcmFiYWpvLmh0bWwiLCBmaWxlID0gIkdyYWZpY28gVHJhYmFqby5wbmciLA0KICAgICAgICBjbGlwcmVjdCA9IGMoMTAsIDMwLCB3aWR0aCArIDUwLCBoZWlnaHQgKyA1MCksDQogICAgICAgIHZ3aWR0aCA9IHdpZHRoLCANCiAgICAgICAgdmhlaWdodCA9IGhlaWdodCkNCndlYnNob3QodXJsID0gIkdyYWZpY28gRXN0dWRpby5odG1sIiwgZmlsZSA9ICJHcmFmaWNvIEVzdHVkaW8ucG5nIiwNCiAgICAgICAgY2xpcHJlY3QgPSBjKDEwLCAzMCwgd2lkdGggKyA1MCwgaGVpZ2h0ICsgNTApLA0KICAgICAgICB2d2lkdGggPSB3aWR0aCwgDQogICAgICAgIHZoZWlnaHQgPSBoZWlnaHQpDQp3ZWJzaG90KHVybCA9ICJHcmFmaWNvIFVuaW9uLmh0bWwiLCBmaWxlID0gIkdyYWZpY28gVW5pb24ucG5nIiwNCiAgICAgICAgY2xpcHJlY3QgPSBjKDEwLCAzMCwgd2lkdGggKyA1MCwgaGVpZ2h0ICsgNTApLA0KICAgICAgICB2d2lkdGggPSB3aWR0aCwgDQogICAgICAgIHZoZWlnaHQgPSBoZWlnaHQpDQp3ZWJzaG90KHVybCA9ICJHcmFmaWNvIERpdm9yY2lvLmh0bWwiLCBmaWxlID0gIkdyYWZpY28gRGl2b3JjaW8ucG5nIiwNCiAgICAgICAgY2xpcHJlY3QgPSBjKDEwLCAzMCwgd2lkdGggKyA1MCwgaGVpZ2h0ICsgNTApLA0KICAgICAgICB2d2lkdGggPSB3aWR0aCwgDQogICAgICAgIHZoZWlnaHQgPSBoZWlnaHQpDQp3ZWJzaG90KHVybCA9ICJHcmFmaWNvIEZhbWlsaWFyLmh0bWwiLGZpbGUgPSAiR3JhZmljbyBGYW1pbGlhci5wbmciLA0KICAgICAgICBjbGlwcmVjdCA9IGMoMTAsIDMwLCB3aWR0aCArIDUwLCBoZWlnaHQgKyA1MCksDQogICAgICAgIHZ3aWR0aCA9IHdpZHRoLCANCiAgICAgICAgdmhlaWdodCA9IGhlaWdodCkNCmBgYCANCg0KIyMgTW9kZWxvIGplcsOhcnF1aWNvDQoNClNlIHV0aWxpemEgbGEgZnVuY2nDs24gYGh0cygpYCBwYXJhIGNyZWFyIHVuYSBzZXJpZSBkZSB0aWVtcG8gamVyw6FycXVpY2EuIA0KDQpEb25kZSBzZSB1dGlsaXphbiBsb3MgZGF0b3MgZGUgw7psdGltbyBuaXZlbCB5IHNlIHV0aWxpemEgZWwgYXJndW1lbnRvIGBjaGFyYWN0ZXJzYCBkb25kZSBsb3MgcHJpbWVyb3MgZG9zIGNhcmFjdGVyZXMgY29ycmVzcG9uZGVuIGFsIHByaW1lciBuaXZlbCAoUmVnacOzbiksIGxvcyBzaWd1aWVudGVzIGRvcyBjb3JyZXNwb25kZW4gYWwgc2VndW5kbyBuaXZlbCAoQ2l1ZGFkZXMpIHkgY29tbyDDumx0aW1vIGxvcyB0cmVzIGNhcmFjdGVyZXMgY29ycmVzcG9uZGVuIGFsIG1vdGl2byBkZSBsYSBhdXNlbmNpYS4gICANCg0KJFxidWxsZXQkIFRSQT0gIlRyYWJham8iICAgDQokXGJ1bGxldCQgRVNUPSAiRXN0dWRpbyIgICANCiRcYnVsbGV0JCBVTkk9ICJTZSBjYXPDsyBvIHVuacOzIiAgIA0KJFxidWxsZXQkIERJVj0gIlNlIGRpdm9yY2nDsyBvIHNlcGFyw7MiICAgIA0KJFxidWxsZXQkIEZBTT0gIlJldW5pcnNlIGNvbiB1biBmYW1pbGlhciIgICAgICANCg0KYGBge3IsZWNobyA9IFRSVUV9DQpSZWdpb25lcyA8LSByZXAoYyhyZXAoIkNFIiwgNyksDQogICAgICAgICAgICAgICAgICByZXAoIk5FIiwgNSksDQogICAgICAgICAgICAgICAgICByZXAoIk5XIiwgNSksDQogICAgICAgICAgICAgICAgICByZXAoIldFIiwgOCksDQogICAgICAgICAgICAgICAgICByZXAoIlNPIiwgNykpLCA1KQ0KQ2l1ZGFkZXMgPC0gcmVwKGMoIjExIiwgCSIyNCIsIAkiMDEiLCAJIjMyIiwgCSIwNCIsIAkiMTQiLCAJIjI5IiwNCiAgICAgICAgICAgICAgICAgICIyMSIsIAkiMDMiLCAJIjA2IiwgCSIxNSIsIAkiMDkiLA0KICAgICAgICAgICAgICAgICAgIjA4IiwgCSIxOSIsIAkiMjAiLCAJIjMwIiwgCSIxOCIsIAkNCiAgICAgICAgICAgICAgICAgICIxMiIsIAkiMjciLCAJIjAyIiwgCSIwNSIsIAkiMTMiLCAJIjI4IiwgCSIyMiIsIAkiMjYiLCAJDQogICAgICAgICAgICAgICAgICAiMzEiLCAJIjIzIiwgCSIwNyIsIAkiMjUiLCAJIjE3IiwgCSIxMCIsIAkiMTYiKSwgNSkNCg0KTW90aXZvIDwtIGMocmVwKCJUUkEiLCAzMiksDQogICAgICAgICAgICByZXAoIkVTVCIsIDMyKSwNCiAgICAgICAgICAgIHJlcCgiVU5JIiwgMzIpLA0KICAgICAgICAgICAgcmVwKCJESVYiLCAzMiksDQogICAgICAgICAgICByZXAoIkZBTSIsIDMyKSkNCg0Kbm9tYnJlcyA8LSBwYXN0ZTAoUmVnaW9uZXMsIENpdWRhZGVzLCBNb3Rpdm8pICNMYXJnbyBkZSA3IHwgUmVnaW9uZXM9MnxDaXVkYWRlcz0yfE1vdGl2bz0zDQpjb2xuYW1lcyh0cy5teWRhdGEpIDwtIG5vbWJyZXMNCg0Kbm9kZXMgPC0gbGlzdCgxNjAsIGMoNSwgMzIsIDUpKSAjMTYwIHZhcmlhYmxlcyB8UmVnaW9uZXM9NXxDaXVkYWRlcz0zMnxNb3Rpdm9zPTV8ICANCk1vZGVsbzIgPC0gaHRzKHRzLm15ZGF0YSwgbm9kZXMgPSBub2RlcyxjaGFyYWN0ZXJzID0gYygyLCAyLCAzKSkNCg0KI0NhbWJpYW1vcyBsb3MgbGFiZWxzIA0KTW9kZWxvMiRsYWJlbHMkYExldmVsIDFgIDwtIGMoIkNlbnRybyIsICJOb3Jlc3RlIiwgIk5vcm9lc3RlIiwgIlN1cmVzdGUiLCAiT2NjaWRlbnRlIikNCmBgYA0KDQojIyMgTml2ZWwgMTogUmVnacOzbiAgDQoNCmBgYHtyfQ0KTW9kZWxvMiAlPiUgDQogYWdndHMobGV2ZWwgPSAxKSAlPiUNCiAgYXV0b3Bsb3Qoc2l6ZSA9IDEpICsgDQogICB0aGVtZV9jbGFzc2ljKCkgKyANCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwNCiAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMiwgImNtIikpICsNCiAgICAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkgKyANCiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwoNSwgIkRhcmsyIikpICsgDQogICAgICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDA1LCAyMDE5LCBieSA9IDIpKSArDQogICAgICAgIGxhYnModGl0bGUgPSAiTW90aXZvIGRlIGxhIGF1c2VuY2lhIDIwMDUtMjAxOSIsDQogICAgICAgICAgICAgc3VidGl0bGUgPSAiVHJhYmFqbyAvIEVzdHVkaW8gLyBTZSBjYXPDsyBvIHVuacOzIC8gRGl2b3JjacOzIG8gc2VwYXLDsyAvIFJldW5pcnNlIGNvbiB1biBmYW1pbGlhciIsDQogICAgICAgICAgICAgeSA9ICJSYXRlIiwNCiAgICAgICAgICAgICB4ID0gIlllYXIiLA0KICAgICAgICAgICAgIGNvbG9yID0gIlNlcmllcyIpIA0KYGBgDQoNCiMjIE5pdmVsIDI6IEN1aWRhZCBhdXRvcmVwcmVzZW50YWRhICANCg0KYGBge3J9DQpNb2RlbG8yICU+JSANCiBhZ2d0cyhsZXZlbCA9IDIpICU+JQ0KICBhdXRvcGxvdChzaXplID0gMC41KSArIA0KICAgdGhlbWVfY2xhc3NpYygpICsgDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksDQogICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsICJsaW5lcyIpLA0KICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArDQogICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOCwgIkRhcmsyIikpKDYwKSkgKyANCiAgICAgIGd1aWRlcyhjb2wgPSBndWlkZV9sZWdlbmQobmNvbCA9IDE1KSkrDQogICAgICAgbGFicyh0aXRsZSA9ICJNb3Rpdm8gZGUgbGEgYXVzZW5jaWEgMjAwNS0yMDE5IiwNCiAgICAgICAgICAgIHN1YnRpdGxlID0gIlRyYWJham8gLyBFc3R1ZGlvIC8gU2UgY2Fzw7MgbyB1bmnDsyAvIERpdm9yY2nDsyBvIHNlcGFyw7MgLyBSZXVuaXJzZSBjb24gdW4gZmFtaWxpYXIiLA0KICAgICAgICAgICAgeSA9ICJSYXRlIiwNCiAgICAgICAgICAgIHggPSAiWWVhciIsDQogICAgICAgICAgICBjb2xvciA9ICJTZXJpZXMiKSANCmBgYA0KDQpTaSBiaWVuIGxhIGdyw6FmaWNhIGFudGVyaW9yIG5vIHBlcm1pdGUgc3UgaW50ZXJwcmV0YWJpbGlkYWQgZGViaWRvIGEgcXVlIHRvZG8gZWwgZW5zYW1ibGUgZGUgbGFzIHNlcmllcyBlc3TDoW4gbXV5IGp1bnRhcy4gDQoNCkhhY2llbmRvIHVzbyBkZSBsYSBmdW5jacOzbiBgYWdndHNgIGV4dHJhZSBsYXMgc2VyaWVzIHRlbXBvcmFsZXMgZGUgdW4gb2JqZXRvIGBodHNgIHBhcmEgY3VhbHF1aWVyIG5pdmVsIGRlIGRlc2FncmVnYWNpw7NuLiANCg0KYGBge3IsZWNobyA9IFRSVUV9DQpncm91cHMgPC0gYWdndHMoTW9kZWxvMiwgbGV2ZWwgPSAyKQ0KYGBgDQoNCmBgYHtyLGZpZy53aWR0aCA9IDEwLGZpZy5oZWlnaHQgPSAxMn0NCnRpYmJsZTo6YXNfdGliYmxlKGdyb3VwcykgJT4lDQogdGlkeXI6OmdhdGhlcihTZXJpZXMpICU+JQ0KICBtdXRhdGUoRGF0ZSA9IHJlcCh0aW1lKGdyb3VwcyksIE5DT0woZ3JvdXBzKSksDQogICAgICAgICBHcm91cCA9c3RyaW5ncjo6c3RyX2V4dHJhY3QoU2VyaWVzLCAiKFtBLVphLXogXSopIikpICU+JQ0KICAgZ2dwbG90KGFlcyh4ID0gRGF0ZSwgeSA9IHZhbHVlLCBncm91cCA9IFNlcmllcywgY29sb3VyID0gU2VyaWVzKSkgKw0KICAgIGdlb21fbGluZSgpICsgDQogICAgIHRoZW1lX2NsYXNzaWMoKSArDQogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpLA0KICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLA0KICAgICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsICJsaW5lcyIpLA0KICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgICAgICBzY2FsZV9jb2xvcl92aXJpZGlzX2QoKSArDQogICAgICAgI3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOCwgIkRhcmsyIikpKDMzKSkgKyANCiAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxOTgwLCAyMDE1LCBieSA9IDUpKSArDQogICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKw0KICAgICAgICAgIGd1aWRlcyhjb2wgPSBndWlkZV9sZWdlbmQobmNvbCA9IDE1KSkrDQogICAgICAgICAgIGxhYnModGl0bGUgPSAiTW90aXZvIGRlIGxhIGF1c2VuY2lhIDIwMDUtMjAxOSIsDQogICAgICAgICAgICAgICAgc3VidGl0bGUgPSAiVHJhYmFqbyAvIEVzdHVkaW8gLyBTZSBjYXPDsyBvIHVuacOzIC8gRGl2b3JjacOzIG8gc2VwYXLDsyAvIFJldW5pcnNlIGNvbiB1biBmYW1pbGlhciIsDQogICAgICAgICAgICAgICAgeSA9ICJSYXRlIiwNCiAgICAgICAgICAgICAgICB4ID0gIlllYXIiLA0KICAgICAgICAgICAgICAgIGNvbG9yID0gIlNlcmllcyIpICsNCiAgICAgICAgICAgIGZhY2V0X3dyYXAoLiB+IEdyb3VwKSANCmBgYA0KDQojIyBOaXZlbCAzOiBNb3Rpdm8gZGUgbGEgYXVzZW5jaWEgICAgDQoNCkVuIG1vZGVsbyBnZW5lcmFsLCBzZSBlc3TDoW4gdHJhYmFqYW5kbyBjb24gdHJlcyBuaXZlbGVzIGRlIGRlc2FncmVnYWNpw7NuIChNb3Rpdm8gZGUgdHJhYmFqbywgUmVnaW9uZXMgeSBDaXVkYWRlcykgeSBiaWVuIHVuIE5pdmVsIENlcm8gKFRvdGFsKS4NCmBgYHtyLGVjaG8gPSBUUlVFfQ0KZ3JvdXBzIDwtIGFnZ3RzKE1vZGVsbzIsIGxldmVsID0gMykNCmBgYA0KDQpgYGB7cixmaWcud2lkdGggPSAxMCxmaWcuaGVpZ2h0ID0gMTJ9DQojaHR0cHM6Ly9zdHJpbmdyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL3N0cl9sb2NhdGUuaHRtbA0KdGliYmxlOjphc190aWJibGUoZ3JvdXBzKSAlPiUNCiB0aWR5cjo6Z2F0aGVyKFNlcmllcykgJT4lIA0KICBtdXRhdGUoRGF0ZSA9IHJlcCh0aW1lKGdyb3VwcyksIE5DT0woZ3JvdXBzKSksDQogICAgICAgICBHcm91cCA9c3RyaW5ncjo6c3RyX2V4dHJhY3QoU2VyaWVzLCAiKFtBLVphLXogXSopIiksDQogICAgICAgICBNb3Rpdm89c3RyaW5ncjo6c3RyX3N1YihTZXJpZXMsNSwgNykpICU+JQ0KICAgZ2dwbG90KGFlcyh4ID0gRGF0ZSwgeSA9IHZhbHVlLCBncm91cCA9IFNlcmllcywgY29sb3VyID0gU2VyaWVzKSkgKw0KICAgIGdlb21fbGluZSgpICsgDQogICAgIHRoZW1lX2NsYXNzaWMoKSArDQogICAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpLA0KICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLA0KICAgICAgICAgICAgbGVnZW5kLmtleS53aWR0aD11bml0KDAuMiwgImNtIiksDQogICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMCwgImNtIiksDQogICAgICAgICAgICBsZWdlbmQuc3BhY2luZy54ID0gdW5pdCgwLCAiY20iKSwNCiAgICAgICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC41LCAibGluZXMiKSwNCiAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArDQogICAgICAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkgKw0KICAgICAgICNzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDgsICJEYXJrMiIpKSgxNjApKSArIA0KICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDE5ODAsIDIwMTUsIGJ5ID0gNSkpICsNCiAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSArDQogICAgICAgICAgZ3VpZGVzKGNvbCA9IGd1aWRlX2xlZ2VuZChuY29sID0gMTUpKSsNCiAgICAgICAgICAgbGFicyh0aXRsZSA9ICJNb3Rpdm8gZGUgbGEgYXVzZW5jaWEgMjAwNS0yMDE5IiwNCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICJUcmFiYWpvIC8gRXN0dWRpbyAvIFNlIGNhc8OzIG8gdW5pw7MgLyBEaXZvcmNpw7MgbyBzZXBhcsOzIC8gUmV1bmlyc2UgY29uIHVuIGZhbWlsaWFyIiwNCiAgICAgICAgICAgICAgICB5ID0gIlJhdGUiLA0KICAgICAgICAgICAgICAgIHggPSAiWWVhciIsDQogICAgICAgICAgICAgICAgY29sb3IgPSAiU2VyaWVzIikgKw0KICAgICAgICAgICAgZmFjZXRfd3JhcCguIH4gR3JvdXAgKyBNb3Rpdm8pIA0KYGBgDQoNCkFuYWxpemFuZG8gbGEgZ3LDoWZpY2EgYW50ZXJpb3IgZWwgbW90aXZvIGRlIGF1c2VuY2lhIHBhcmEgIlJldW5pcnNlIGNvbiB1biBmYW1pbGlhciIgZXMgbGEgcXVlIHByZXNlbnRhIHVuIG1heW9yIG7Dum1lcm8gZGUgY2Fzb3MgbWlncmF0b3Jpb3MiIGNvbiByZXNwZWN0byBhIGxvcyBvdHJvcyBjdWF0cm8gY2Fzb3MuICAgICAgDQoNCg0KYGBge3J9DQojcHJpbnQoTW9kZWxvMikNCiNzbWF0cml4KE1vZGVsbzIpDQojYWxsdHMoTW9kZWxvMikNCmBgYA0KDQojIyBGb3JlY2FzdGluZzogTW90aXZvIGRlIGxhIGF1c2VuY2lhIGVuIGdlbmVyYWwgICANCg0KU2UgZXNwZXJhIHF1ZSBsb3MgcHJvbsOzc3RpY29zIHNlYW4gY29uc2lzdGVudGVzIGNvbiBsYSBlc3RydWN0dXJhIGRlIGFncmVnYWNpw7NuIGRlIGxhcyBzZXJpZXMgZGUgIHRpZW1wbyBhbCBhZ3J1cGFybGFzLiAgIA0KDQpgYGB7ciwgZWNobyA9IFRSVUV9DQojaD1mb3Jlc2Nhc3QgaG9yaXpvbg0KI21ldGhvZDwtIm1vIiwgImJ1IiwgInRkZnAiDQpmLm1vZGVsbzIgPC0gZm9yZWNhc3QoTW9kZWxvMiwgaCA9IDEwLCBtZXRob2QgPSAibW8iLCBsZXZlbCA9IDIsIGZtZXRob2QgPSAiYXJpbWEiLCBwYXJhbGxlbCA9IFRSVUUsIGtlZXAuZml0dGVkID0gVFJVRSkNCmBgYA0KDQpgYGB7cixlY2hvID0gVFJVRSwgZXZhbCA9IEZBTFNFfQ0Kc3VtbWFyeShmLm1vZGVsbzIpDQpgYGANCg0KIyMjIE5pdmVsIDAgYWwgMjogVG90YWwgLyBSZWdpw7NuIC8gQ2l1ZGFkICANCg0KYGBge3IsZWNobyA9IFRSVUV9DQpmY3N0MiA8LSBhZ2d0cyhmLm1vZGVsbzIsIGxldmVscyA9IDA6MikNCmdyb3VwcyA8LSBhZ2d0cyhNb2RlbG8yLCBsZXZlbHMgPSAwOjIpDQpgYGANCg0KYGBge3IsZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4fQ0KYXV0b3Bsb3QoZmNzdDIsIHNpemUgPSAwLjUpICsNCiBhdXRvbGF5ZXIoZ3JvdXBzKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMTksY29sb3IgPSAiI0E4QUJENyIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgIHRoZW1lX2NsYXNzaWMoKSArDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksDQogICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjUsICJsaW5lcyIpLA0KICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArDQogICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsgDQogICAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDUsIDIwMjUsIGJ5ID0gMikpICsNCiAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKw0KICAgICAgICBndWlkZXMoY29sID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAxNSkpKw0KICAgICAgICAgbGFicyh0aXRsZSA9ICJNb3Rpdm8gZGUgbGEgYXVzZW5jaWEgMjAwNS0yMDE5IiwNCiAgICAgICAgICAgICAgc3VidGl0bGUgPSAiVHJhYmFqbyAvIEVzdHVkaW8gLyBTZSBjYXPDsyBvIHVuacOzIC8gRGl2b3JjacOzIG8gc2VwYXLDsyAvIFJldW5pcnNlIGNvbiB1biBmYW1pbGlhciIsDQogICAgICAgICAgICAgIHkgPSAiUmF0ZSIsDQogICAgICAgICAgICAgIHggPSAiWWVhciIsDQogICAgICAgICAgICAgIGNvbG9yID0gIlNlcmllcyIpIA0KYGBgDQoNCg0KYGBge3IsZWNobyA9IFRSVUV9DQp0YWJsYSA8LSB0cyhyYmluZChncm91cHMsIGZjc3QyKSwNCiAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gc3RhcnQoZ3JvdXBzKSwgZnJlcXVlbmN5ID0gNCkgI0ZyZWN1ZW5jaWEgYWwgYcOxbw0KYGBgDQoNCiMjIyBOaXZlbCAwOiBUb3RhbCBkZSBjYXNvcyBkZSBtaWdyYWNpw7NuICANCg0KYGBge3J9DQojaHR0cDovL3d3dy5zdGhkYS5jb20vZW5nbGlzaC93aWtpL2dncGxvdDItbGluZS10eXBlcy1ob3ctdG8tY2hhbmdlLWxpbmUtdHlwZXMtb2YtYS1ncmFwaC1pbi1yLXNvZnR3YXJlDQphdXRvcGxvdCh0YWJsYVssICJUb3RhbCJdLCBjb2xvdXIgPSAiIzE3MjBCNyIsIHNpemUgPSAxLjIsIGFscGhhID0gMC42LCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArICAgICAgDQogZ2VvbV92bGluZSh4aW50ZXJjZXB0PTIwMTkuNSxjb2xvciA9ICIjQThBQkQ3IixsaW5ldHlwZT0gImRhc2hlZCIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKyANCiAgICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDA1LCAyMDI1LCBieSA9IDIpKSArDQogICAgIGxhYnModGl0bGUgPSAiTW90aXZvIGRlIGxhIGF1c2VuY2lhIDIwMDUtMjAxOSIsDQogICAgICAgICAgc3VidGl0bGUgPSAiVHJhYmFqbyAvIEVzdHVkaW8gLyBTZSBjYXPDsyBvIHVuacOzIC8gRGl2b3JjacOzIG8gc2VwYXLDsyAvIFJldW5pcnNlIGNvbiB1biBmYW1pbGlhciIsDQogICAgICAgICAgeSA9ICJSYXRlIiwNCiAgICAgICAgICB4ID0gIlllYXIiLA0KICAgICAgICAgIGNvbG9yID0gIlNlcmllcyIpIA0KYGBgDQoNCiMjIyBOaXZlbCAxIGEgMjogTml2ZWwgcmVnacOzbiB5IG5pdmVsIGNpdWRhZCAgICANCg0KYGBge3IsZmlnLndpZHRoID0gMTAsZmlnLmhlaWdodCA9IDV9DQphc190aWJibGUodGFibGFbLC0xXSkgJT4lDQogdGlkeXI6OmdhdGhlcihTZXJpZXMpICU+JQ0KICBtdXRhdGUoRGF0ZSA9IHJlcCh0aW1lKHRhYmxhKSwgTkNPTCh0YWJsYSktMSksDQogICAgICAgICBHcm91cCA9IHN0cl9leHRyYWN0KFNlcmllcywgIihbQS1aYS16IF0qKSIpKSAlPiUNCiAgIGdncGxvdChhZXMoeCA9IERhdGUsIHkgPSB2YWx1ZSwgZ3JvdXAgPSBTZXJpZXMsIGNvbG91ciA9IFNlcmllcykpICsNCiAgICBnZW9tX2xpbmUoKSArDQogICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMTksY29sb3IgPSAiI0E4QUJENyIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgICAgIHRoZW1lX2NsYXNzaWMoKSArIA0KICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSwNCiAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksDQogICAgICAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMC4yLCAiY20iKSwNCiAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMCwgImNtIiksDQogICAgICAgICAgICAgbGVnZW5kLnNwYWNpbmcueCA9IHVuaXQoMC4xLCAiY20iKSwNCiAgICAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwgImxpbmVzIiksDQogICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgICAgICAgc2NhbGVfY29sb3JfdmlyaWRpc19kKCkgKw0KICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDA1LCAyMDI1LGJ5ID0gNSkpICsNCiAgICAgICAgICBndWlkZXMoY29sID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAxNSkpICsNCiAgICAgICAgICAgbGFicyh0aXRsZSA9ICJNb3Rpdm8gZGUgbGEgYXVzZW5jaWEgMjAwNS0yMDE5IiwNCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICJUcmFiYWpvIC8gRXN0dWRpbyAvIFNlIGNhc8OzIG8gdW5pw7MgLyBEaXZvcmNpw7MgbyBzZXBhcsOzIC8gUmV1bmlyc2UgY29uIHVuIGZhbWlsaWFyIiwNCiAgICAgICAgICAgICAgICB5ID0gIlJhdGUiLA0KICAgICAgICAgICAgICAgIHggPSAiWWVhciIsDQogICAgICAgICAgICAgICAgY29sb3IgPSAiU2VyaWVzIikgKw0KICAgICAgICAgICAgZmFjZXRfd3JhcCguIH4gR3JvdXApIA0KYGBgDQoNCiMjIyBOaXZlbCAzOiBNb3Rpdm9zIGRlIGF1c2VuY2lhIGVuIGdlbmVyYWwgICANCg0KYGBge3IsZWNobyA9IFRSVUV9DQpmY3N0MyA8LSBhZ2d0cyhmLm1vZGVsbzIsIGxldmVscyA9IDMpDQpncm91cHMgPC0gYWdndHMoTW9kZWxvMiwgbGV2ZWxzID0gMykNCnRhYmxhIDwtIHRzKHJiaW5kKGdyb3VwcywgZmNzdDMpLCBzdGFydCA9IHN0YXJ0KGdyb3VwcyksIGZyZXF1ZW5jeSA9IDQpICNGcmVjdWVuY2lhIGFsIGHDsW8NCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoID0gMTMsZmlnLmhlaWdodCA9IDEzfQ0KYXNfdGliYmxlKHRhYmxhWywtMV0pICU+JQ0KIHRpZHlyOjpnYXRoZXIoU2VyaWVzKSAlPiUNCiAgbXV0YXRlKERhdGUgPSByZXAodGltZSh0YWJsYSksIE5DT0wodGFibGEpIC0gMSksDQogICAgICAgICBHcm91cCA9IHN0cl9leHRyYWN0KFNlcmllcywgIihbQS1aYS16IF0qKSIpLA0KICAgICAgICAgTW90aXZvID0gc3RyaW5ncjo6c3RyX3N1YihTZXJpZXMsIDUsIDcpKSAlPiUNCiAgIGdncGxvdChhZXMoeCA9IERhdGUsIHkgPSB2YWx1ZSwgZ3JvdXAgPSBTZXJpZXMsIGNvbG91ciA9IFNlcmllcykpICsNCiAgICBnZW9tX2xpbmUoKSArDQogICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMTksIGNvbG9yID0gIiNBOEFCRDciLCBsaW5ldHlwZT0gImRhc2hlZCIpICsNCiAgICAgIHRoZW1lX2NsYXNzaWMoKSArIA0KICAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0PTEpLA0KICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwNCiAgICAgICAgICAgICBsZWdlbmQua2V5LndpZHRoPXVuaXQoMC4yLCAiY20iKSwNCiAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMCwgImNtIiksDQogICAgICAgICAgICAgbGVnZW5kLnNwYWNpbmcueCA9IHVuaXQoMC4xLCAiY20iKSwNCiAgICAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMDEsICJsaW5lcyIpLA0KICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArDQogICAgICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsNCiAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwNSwgMjAyNSxieSA9IDUpKSArDQogICAgICAgICAgZ3VpZGVzKGNvbCA9IGd1aWRlX2xlZ2VuZChuY29sID0gMTUpKSArDQogICAgICAgICAgIGxhYnModGl0bGUgPSAiTW90aXZvIGRlIGxhIGF1c2VuY2lhIDIwMDUtMjAxOSIsDQogICAgICAgICAgICAgICAgc3VidGl0bGUgPSAiVHJhYmFqbyAvIEVzdHVkaW8gLyBTZSBjYXPDsyBvIHVuacOzIC8gRGl2b3JjacOzIG8gc2VwYXLDsyAvIFJldW5pcnNlIGNvbiB1biBmYW1pbGlhciIsDQogICAgICAgICAgICAgICAgeSA9ICJSYXRlIiwNCiAgICAgICAgICAgICAgICB4ID0gIlllYXIiLA0KICAgICAgICAgICAgICAgIGNvbG9yID0gIlNlcmllcyIpICsNCiAgICAgICAgICAgIGZhY2V0X3dyYXAoLn4gR3JvdXAgKyBNb3Rpdm8pDQpgYGANCg0KDQojIFJlZmVyZW5jaWFzDQoNCkVuY3Vlc3RhIE5hY2lvbmFsIGRlIE9jdXBhY2nDs24geSBFbXBsZW8gKEVOT0UpLCBwb2JsYWNpw7NuIGRlIDE1IGHDsW9zIHkgbcOhcyBkZSBlZGFkLiAobi5kLikuIFJldHJpZXZlZCBNYXJjaCAzMCwgMjAyMCwgZnJvbSBodHRwczovL3d3dy5pbmVnaS5vcmcubXgvcHJvZ3JhbWFzL2Vub2UvMTV5bWFzLyAgDQoNCkZvcmVjYXN0aW5nIEhpZXJhcmNoaWNhbCBUaW1lIFNlcmllcyB1c2luZyBSIC0gQnJpbGxpbyBEYXRhIFNjaWVuY2UgLSBNZWRpdW0uIChuLmQuKS4gUmV0cmlldmVkIE1hcmNoIDMwLCAyMDIwLCBmcm9tIGh0dHBzOi8vbWVkaXVtLmNvbS9icmlsbGlvLWRhdGEtc2NpZW5jZS9mb3JlY2FzdGluZy1oaWVyYXJjaGljYWwtdGltZS1zZXJpZXMtdXNpbmctci01OTg4MjhkYmE0MzUgICANCiANCiMgTGlicmVyw61hcyAgDQoNCioqTGlicmVyw61hcyBxdWUgc2UgdXNhcm9uIGVuIGVsIHRyYWJham8qKiAgIA0KDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0KbmFtZXMoc2Vzc2lvbkluZm8oKSRvdGhlclBrZ3MpDQpgYGANCg0KTm9zIGhhIHNlcnZpZG8gYSBjb25zdHJ1aXIgbW9kZWxvcyBkZSBzZXJpZXMgZGUgdGllbXBvIGNvbiBkYXRvcyBlc3RydWN0dXJhbGVzIHBhcmEgZmluZXMgZGUgcHJvbsOzc3RpY29zLiANCg0KDQoNCjxhIHJlbD0gImxpY2Vuc2UiIGhyZWY9ICJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS80LjAvIj48aW1nIHNyYz0gImh0dHBzOi8vaS5jcmVhdGl2ZWNvbW1vbnMub3JnL2wvYnkvNC4wLzg4eDMxLnBuZyIgYWx0PSAiQ3JlYXRpdmUgQ29tbW9ucyBMaWNlbmNlIiBzdHlsZT0gImJvcmRlci13aWR0aDowIi8+PC9hPjxiciAvPlRoaXMgd29yayBieSBbKipEaWFuYSBWaWxsYXNhbmEgT2NhbXBvKipde3htbG5zOmNjPSAiaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiBwcm9wZXJ0eSA9ICJjYzphdHRyaWJ1dGlvbk5hbWUifSBpcyBsaWNlbnNlZCB1bmRlciBhIDxhIHJlbD0gImxpY2Vuc2UiIGhyZWY9ICJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS80LjAvIj5DcmVhdGl2ZSBDb21tb25zIEF0dHJpYnV0aW9uIDQuMCBJbnRlcm5hdGlvbmFsIExpY2Vuc2U8L2E+Lg0KDQo=